I literally took 4 hours to debug this in React JS. I am sharing a simplified code to reproduce the same scenario. The following code is a state variable and its setter function; Have a look at it:
const [arr, setArr] = useState([]);
setArr(prevArr => {
prevArr.push(10);
return prevArr;
})
The above code is supposed to add 10 into the state variable arr
. But, it just adds 10
two times into the array. So, after the setArr
worked, the new value of arr
is [10, 10]
.
I spent 4 hours to check if there were leaks in useEffect
(that I am using in my code), or something else, until I found that the following code works as intended:
setArr(prevArr => {
return [...prevArr, number];
})
Can anyone explain me this behaviour? Also, are there any similar cases that I might experience in future as a react developer?
2
Answers
Array.push()
method pushes the object passed in as a parameter into the same reference of the original array. Whereas, when using a spread operator it creates a new array with a copy of the old array.Let’s understand this example:
Here, we’re returning a value like this:
[]
which indicates JS to create a new array, then we’re spreading the entries of previous array using the spread operator:[...prevArr]
which indicates to copy all the entries ofprevArr
into this newly created array, and finally passing a new value:[...prevArr, number]
will add a new element in the array apart from the other copied elements.if you use prevArr.push and return prevArr, it means the array object is still old one.
so react will bailout this state, meaning don’t trigger rerender on this situation.