问题描述
遇到一个问题,我的状态中有一个具有多个值的对象,但我只需要监听一个更改。
示例:
在第一次重新渲染时,我可能会看到类似的内容。
loading: {
objectone: false,objecttwo: false,objectthree: false,}
在我第二次重新渲染时,我可能会看到状态更改为如下所示:}
loading: {
objectone: true,}
然后状态会进一步变化,将其他两个对象更新为 true。
loading: {
objectone: true,objecttwo: true,objectthree: true,}
每次加载状态中的一个对象发生变化时,它都会在我的 useSelector 中重新渲染。
如果我只想要第一个对象 objectone
中的信息。我如何在 useSelector 中编写它,以便在其他两个对象更新时不会触发重新渲染?
我尝试过的事情:
之前
const loadingStatus = useSelector(({ loading }) => loading);
之后
const loadingStatus = useSelector(({ loading }) => {
return loading.objectone ? true : false;
});
解决方法
这是一个例子,当 objectone 没有改变时,你的第二个选择器应该可以工作并且不会重新渲染:
const { Provider,useDispatch,useSelector } = ReactRedux;
const { createStore,applyMiddleware,compose } = Redux;
const { createSelector } = Reselect;
const initialState = {
loading: {
objectone: false,objecttwo: false,objectthree: false,},};
//action types
const CHANGE_LOADING = 'CHANGE_LOADING';
//action creators
const changeLoading = (whatLoading) => ({
type: CHANGE_LOADING,payload: whatLoading,});
const reducer = (state,{ type,payload }) => {
if (type === CHANGE_LOADING) {
return {
...state,loading: {
...state.loading,[payload]: !state.loading[payload],};
}
return state;
};
//selectors
const selectLoading = (state) => state.loading;
const createSelectWhatLoading = (what) =>
createSelector(
[selectLoading],(loading) => loading[what]
);
//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 Loading = React.memo(function Loading() {
console.log('rendeing loading');
const dispatch = useDispatch();
const selectObjectOne = React.useMemo(
() => createSelectWhatLoading('objectone'),[]
);
const objectone = useSelector(selectObjectOne);
return (
<div>
<p>objectone is {String(objectone)}</p>
<button
onClick={() => dispatch(changeLoading('objectone'))}
>
Change objectone
</button>
<button
onClick={() =>
dispatch(changeLoading('objecttwo'))
}
>
Change objecttwo
</button>
</div>
);
});
const App = () => {
return <Loading />;
};
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>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>