-1

Shouldn't these do the same thing? The first code snippet causes my component to rerender

const context = React.useContext(myContext);
const { arr, setArr } = context;

const addItem = (item) => {
    arr[0].subArr.push(item);
    setArr([...arr]);
}

but this does not

const context = React.useContext(myContext);
const { arr, setArr } = context;

const addItem = (item) => {
    arr[0].subArr.push(item);
    setArr(arr);
}

setArr is just pulled from React.useState() there's no custom functionality I built

William
  • 61
  • 1
  • 6
  • The first is a new array reference, the second is the current state array reference. They both are state mutations. React uses shallow object equality for diffing purposes. – Drew Reese Oct 12 '20 at 05:41

2 Answers2

3

React will only re-render a component if at least item in its state (or context) changes. If all previous state values are === to the new state, React will not call the functional component at all and simply keep using what was rendered the last time.

This is one of the reasons you should never mutate state in React - it can lead to unexpected or unpredictable behavior.

In your case, when you do setArr(arr), since the arr is the exact same array that's currently in state context, React skips re-rendering because the new state is === to the old state. Only by creating a new array which is not === to what is currently in state does a re-render occur.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Here is a brief article on why arrays with the same values are not considered equal in JS: https://dev.to/shubhamtiwari909/2-arrays-of-same-value-are-not-equal-in-js-518c#:~:text=because%20everything%20in%20javascript%20is,false%20in%20both%20the%20cases. – jared Nov 01 '22 at 16:19
1

To understand this you have understood how arrays are being treated in JS. In plain English, when you create an array JS knows the array reference, which is the memory address where the array is being stored. Now although you are changing the items in the array it doesn't change the reference. When JS tries to find that array it finds it in the old location. Therefore, from JS perspective the array is not changed although the items are changed. And we know that react doesn't re-render unless there is a change in the state. So, when you write setState(arr), react finds that the array reference is not changed therefore no re-render.

On the other hand, when you write setState([...arr]), we are creating a new array with the items of the arr array. So, in this case, react finds out that the array reference is changed. So, it re-renders.

For better understanding, you should read this thread.

Md Sabbir Alam
  • 4,937
  • 3
  • 15
  • 30