React+Redux自定义挂钩(仅在特定条件下更新)



我有一个组件,如下所示:

function Comp() {
const counter = useSelector(state => state.counter);
console.log('I will only re-render on change of state.counter, not state.info etc');
return <div>{counter}</div>
}

这仅在state.counter已被改变时重新呈现,即,在redux状态的另一部分被更新时不重新呈现。这很好。

我的渲染函数实际上非常大(而且性能很高——实际上这个组件在很多情况下都会使用(,因此不仅渲染计数器状态。

我想我只想在某些条件下重新渲染,比如计数器becoming 5was recently 5 but just changed to something else。但不在计数器was 3 and now 4上重新应答。

为此,我正在考虑创建一个自定义挂钩,例如:

function useIsCounterFive() {
const counter = useSelector(state => state.counter);
const [counterIsFive, setCounterIsFive] = useState(false);
useEffect(() => {
if(counter === 5) {
setCounterIsFive(true);
}
else {
setCounterIsFalse(false);
}
// Or as an alternative to the above else block:
/*
else if(counterIsFive === true) {
setCounterIsFalse(false);
}
*/
}, [counter])
return counterIsFive;

}

然后让Comp组件看起来像:

function Comp() {
const isFive = useIsCounterFive();
console.log('I only want to be run when isFive changes, the same way as I only was running in the previous example when the _counter_ variable changed');
return <div>bla bla</div>
}

即使计数器从3变为4应该保持false的状态,钩子仍然导致Comp组件重新呈现。我希望在使用useSelector时获得这样的结果,它只会导致我的Comp在所选值发生更改时运行/重新渲染。

有什么见解吗?:(

您可以将选择器道具传递给您的函数,并使用React.memo来记忆该函数,以便在不需要时防止渲染。

function ThatWrapsCounter() {
const counter = useSelector(state => state.count);
return <MemoizedCounter count={count} />
}

function Counter({ count }) {
}
function checkForFive(prevProps, props) {
if (props.count === 5) return true;
return false;
}
const MemoizedCounter = React.memo(Counter, checkForFive);

这里有一个例子,当计数器不是5并且是5时,使用选择器重新渲染:

const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;
const initialState = { count: 0 };
//action types
const ADD = 'ADD';
//action creators
const add = () => ({
type: ADD,
});
const reducer = (state, { type, payload }) => {
if (type === ADD) {
return { ...state, count: state.count + 1 };
}
return state;
};
//selectors
const selectCount = (state) => state.count;
const createSelectCountRule = (rule) =>
createSelector([selectCount], rule);
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(() => (next) => (action) =>
next(action)
)
)
);
const Counter = () => {
const selectCount = React.useMemo(
() => createSelectCountRule((count) => count === 5),
[]
);
const count = useSelector(selectCount);
console.log('Rendering counter with:', count);
return count ? 'count is 5' : 'count is not 5';
};
const App = () => {
const dispatch = useDispatch();
return (
<div>
<button onClick={() => dispatch(add())}>add</button>
<Counter />
</div>
);
};
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>

相关内容

  • 没有找到相关文章

最新更新