如何仅当一个对象在 useSelector 中发生更改时才导致重新渲染
How to cause a rerender only if one object changes in a useSelector
我有一个对象在我的状态下有多个值,但我只需要听一个来改变。
示例:
在第一次重新渲染时,我可能会看到类似这样的东西。
loading: {
objectone: false,
objecttwo: false,
objectthree: false,
}
在第二次重新渲染时,我可能会看到状态更改为如下所示:}
loading: {
objectone: true,
objecttwo: false,
objectthree: false,
}
然后状态进一步改变以将其他两个对象更新为 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>
我有一个对象在我的状态下有多个值,但我只需要听一个来改变。
示例:
在第一次重新渲染时,我可能会看到类似这样的东西。
loading: {
objectone: false,
objecttwo: false,
objectthree: false,
}
在第二次重新渲染时,我可能会看到状态更改为如下所示:}
loading: {
objectone: true,
objecttwo: false,
objectthree: false,
}
然后状态进一步改变以将其他两个对象更新为 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>