如何仅当 useSelector 中的一个对象发生更改时才导致重新渲染

问题描述

遇到一个问题,我的状态中有一个具有多个值的对象,但我只需要监听一个更改。

示例:

在第一次重新渲染时,我可能会看到类似的内容

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>