reactjsobjectstatesetstate

Why is React rerendering the component when the states are the same?


I have an object state inside my react component set up like this:

const [state, setState] = useState({ keyOne: true, keyTwo: 'someKey' })

When I change the state, the component obviously rerenders. But that's the problem. The component is rerendering even if I change the state to the value that it's currently set to. For example, the component still rerenders if I do this:

setState({ keyOne: true, keyTwo: 'someKey' });

I'm guessing this is because I'm passing a new object to setState, and so it will be interpreted as a different state each time even if the content in the object is the same. So I guess my question is:

How can I prevent a component from re-rendering if the new object state has the same content as the original state? Is there a built-in way to do this, or will I have to compare the objects beforehand myself?


Solution

  • It's rerendering because the new object is a different object from the previous object. It may have all the same properties inside of it, but react only compares using Object.is (which is similar to ===)

    If you want to skip the render, you will need to make sure the object reference does not change. For example:

    setState(prev => {
      if (prev.keyOne === true && prev.keyTwo === 'someKey')  {
        return prev; // Same object, so render is skipped
      } else {
        return { keyOne: true, keyTwo: 'someKey' };
      }
    });
    

    If you have some favorite library for checking deep equality (Eg, lodash or ramda), you could shorten it to something like the following. This will be particularly useful if there are a lot of properties you would otherwise need to check:

    setState(prev => {
      const next = { keyOne: true, keyTwo: 'someKey' };
      return R.equals(prev, next) ? prev : next;
    });