Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react redux useSelector rerender even when data does not change

I am using react with redux and redux thunk. I have an action where I am making a network request. With the useSelector I am getting the data from redux store. I have a problem that the component rerenders every time when I dispatch the action. I want that the component only rerenders when data changes. I tried already use shallowEqual as the second argument for useSelector. But it does not work. I have compressed it to minimal example in this sandbox. In the console you can see that the component rerenders with every network request. Here is the codesandbox: https://codesandbox.io/s/useselector-js6j0?file=/src/App.js:885-1294

here is the code:

function LevelThree() {
  console.log(`Level three calls: ${++levelThreeCalls}`);
  const contextData = useSelector(state => state.data);
  console.log(contextData);
  const dispatch = useDispatch();
  useInterval(() => {
    dispatch(updateData());
  }, 1000);

  return (
    <div>
      <button onClick={() => dispatch(updateData())}>Change context</button>
      {contextData[0].userId}
    </div>
  );

}

like image 245
otto Avatar asked Jun 05 '20 11:06

otto


2 Answers

The reason that your component is re-rendering on every update is because you are fetching the data again and updating it in redux store,

Since the reference of data changes, the useSelector function returns you a new value and re-renders the component.

You can pass a deepEqual comparison function as a second argument to useSelector to avoid re-rendering it data hasn't changed

import _ from 'underscore';
...
const contextData = useSelector(state => state.data, _.isEqual);

However, you must carefully use this and measure how frequently your data will be updated otherwise you will add an added calculation in your code which won't even prevent a re-render many times

Working demo

like image 163
Shubham Khatri Avatar answered Oct 09 '22 23:10

Shubham Khatri


When an action is dispatched, useSelector() will do a reference comparison of the previous selector result value and the current result value. If they are different, the component will be forced to re-render. If they are the same, the component will not re-render

like image 33
Kaido Hussar Avatar answered Oct 10 '22 00:10

Kaido Hussar