Reputation: 48
I am trying to create a react context provider within a functional component. I am using the useState hook to provide an array to other components and have an add function that pushes a new value to the array. The array and the add function are both provided through the context provider.
It seems to be that using push with state hooks by doing
var newArray = array
newArray.push("text")
setArray(newArray)
does not cause components using the state to rerender but when using
setArray(array=> [...array, "text"])
the components using array provided through a context provider do update.
Would anyone be able to explain why this is?
Upvotes: 1
Views: 2929
Reputation: 432
Arrays are mutable in javascript, so when you create a variable and point it to an array (like in your example)
var newArray = array
the newArray doesn't actually copy its instance, instead just stores a reference to it. You can see this in a really easy example done in the browser console seen below
When you mutate the array in your example by pushing in a new variable it will just add it to the initial array, mutating the state and not causing a rerender. When React reconciles after you calling setArray to the new array, it sees that the array (reference) is the same and does not cause a rerender.
When you use the spread notation example, you are creating a new array by using []
, just syntactic sugar for new Array
and emptying the items from the old one into the new one. When it compares the old state, with the new one and its new items React sees a difference and rerenders your component.
If however you would prefer to do it the way you initially set out to, you can use the .slice() array function so that a new array is created with the data that exists in the one being called on so it would be var newArray = array.slice()
. If you add an item to the new array and set state it will re render.
Upvotes: 4
Reputation: 22885
Read about state mutation.
In react, you must not mutate state in order to re-render. If you push object in array, that is mutation and it does not creates a new reference for that state variable and react could not determine that whether it has been updated or not. React uses shallow comparison so even if contents of array are different, reference is same. You need to update the reference in order to trigger render.
Upvotes: 0
Reputation: 428
When you set state using spread operator ...
you are creating new object. If you are not using it, and you are setting state with old object React
won't update your components since state property doesn't changed (reference to object doesn't changed). As I said at the beginning, using [... array]
you are actually creating new object (new reference) so React update the state.
Upvotes: 0