When I change the property of an object in an array with react hooks, the component does not re-render.
I consulted my lead tech and he explained that React searches "breadth" over "depth," meaning React sees the object, but it can't see changes to the object's properties.
const [array, setArray] = useState([
{'id': 0, text: '0'},
{'id': 1, text: '1'},
{'id': 2, text: '2'}
]);
I expect this the component to re-render when the state is changed, but the behavior acts as if the array of objects were not changed at all.
If I create a copy of array as newArray and change newArray[2].text = '3' and setArray(newArray), react thinks the array hasn't changed. Thus, the component does not reload.
As a workaround, I use
const [trigger, setTrigger] = useState(false);
setTrigger(!trigger);
to force reload. However, this is a hacky way to reload the component and I want a more React way of doing it.
Thank you advance!
React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.
Conclusion. React's useRef hook is a great tool to persist data between renders without causing a rerender and to manipulate the DOM directly. It should only be used sparingly in situations where React doesn't provide a better alternative.
Inside, useEffect compares the two objects, and since they have a different reference, it once again fetches the users and sets the new user object to the state. The state updates then triggers a re-render in the component.
In version 16.8, React hooks were introduced. Hooks allow a component to be built as a function without the need for classes. This component will need a state variable to track the background color and a ref to store the current timer instance.
I consulted my lead tech and he explained that React searches "breadth" over "depth," meaning React sees the object, but it can't see changes to the object's properties. const [array, setArray] = useState ( [ {'id': 0, text: '0'}, {'id': 1, text: '1'}, {'id': 2, text: '2'} ]);
It looks like you're rendering off of the 'sale' state property. React will not detect an updated state and re-render when there is a change within a nested state object (in this case the 'comments' property).
exactly as @malerba118 said, state hooks will not rerender if you pass the same value/object to it. React encourages an immutable approach to ensure consistency, especially between renders.
What your lead tech meant by "breath over depth" is right.
React monitors only the "reference" changes. When you change a property of an object, the reference is the same.
Think of it as when you do, you can still change a.value
even though it's declared constant.
const a = {value: 'abc'}
a.value = 'xxx'
console.log(a.value) // prints 'xxx'
But you can't do
const a = {value: 'abc'}
a = {something: 'bad'}
š not allowed.
The same applies to an array of objects (or a plain old array).
It's a reference type, thus changing the property of an array element would not change the reference of newArray
.
newArray[2].text = '3' and setArray(newArray)
newArray
still points to the same address space.
So when you create an entire new array using a spread syntax or Array.from
, you create an entire new reference (a copy) and, set a new value, and lastly set the state.
const [array, setArray] = useState([
{'id': 0, text: '0'},
{'id': 1, text: '1'},
{'id': 2, text: '2'}
]);
// ... somewhere else.
const copy = [...array, {'id': 2, ]
// or -> const copy = Array.from(array)
copy[2].text = '3'
setArray(copy)
The code above creates a new copy
of array
state. Setting that copy with updated value will trigger the re-render. (but beware, it creates a "shallow copy", not a "deep copy")
Since your data structure is complex, you might as well use ImmerJS, which lets you change the reference as if you are writing current code.
I think the problem is in how you are copying the array. Arrays in js are reference type
so you can't just do this:
const arr = [1,2,4]
const copy = arr
Cause you are just changing the pointer not the reference itself. Try this:
const copy = [...arr]
Now you are creating a new array with the spread
of every arr
elements. To do that using useState
const Comp = () =>{
const [arr, setArr] = useState([1,2,3,4])
return <button onClick={() => setArr([...arr, 5])}>Change</button>
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With