Search code examples
reduxcss-selectorsredux-toolkit

How can i memoize a value of `useSelector()`?


My code looks something like this:

const countersSelector = () => (store) => store.counters;

const MethodOne = () => {
  // Method: Object destructuring
  const counters = useSelector(countersSelector);

  console.log("render MethodOne");

  useEffect(() => {
    console.log("in useeffect methodone");
  }, [counters]);

  return (
    <div>
      <p>{`firstCounter: ${counters}`}</p>
      <p>{`renders: ${renderCount}`}</p>
    </div>
  );
};

export default MethodOne;

This is the full app: https://codesandbox.io/s/redux-useselector-object-destructuring-example-forked-1m87x

And every time counters object is changed (not its value, but the object reference itself), that useEffect() gets triggered.

Can i memoize it somehow, so that counters will only change if the actual values of store.counters change?


Solution

  • I'm not sure what you're asking for here.

    state.counters changing to a new object reference is how immutable updates work. Immutable updates always require updating _all nested fields. So, if the action is supposed to update rootState.counters.firstCounter, it requires creating a new object for counters and a new object for rootState.

    So, if your selector is state => state.counters, then useSelector will re-render the component every time the counters object changes to a new reference, useEffect will re-run because there is a new reference inside its dependencies array, and that is exactly how this is supposed to work.

    As a side note, your countersSelector is incorrect. It's written as a "factory function" that returns a selector. That means that useSelector will actually be looking at the new function reference, not the value extracted from state.

    Instead, it should just be state => state.counters.