Answer a question

Got an issue where I have an object with multiple values in my state but I only need to listen to one for the change.

Example:

On first re-render I might see something like this.

loading: {
  objectone: false,
  objecttwo: false, 
  objectthree: false, 
}

On my second re-render I might see the state change to something like this:}

    loading: {
      objectone: true,
      objecttwo: false, 
      objectthree: false, 
    }

The state then changes further to update the other two objects to true.

    loading: {
      objectone: true,
      objecttwo: true, 
      objectthree: true, 
    }

Each time one of the objects in the loading state changes it causes a re-render in my useSelector.

If I wanted just the information in the first object objectone. How could I write this in my useSelector so that it doesn't trigger a re-render when the other two objects update?

Things I've tried:

before

  const loadingStatus = useSelector(({ loading }) => loading);

after

  const loadingStatus = useSelector(({ loading }) => {
    return loading.objectone ? true : false;
  });

Answers

Here is an example, your second selector should work and not re render when objectone is not changed:

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>
Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐