DEV Community

Discussion on: Common mistake done while using react hooks

Collapse
 
clarity89 profile image
Alex K.

Agree, this is a common source of confusion among those new to using hooks, fell for it myself a few times :D

I think it's important to understand why it works the way it is.

Behind the hood, React uses Object.is polyfill to compare hook dependencies. This method compares non-primitive values (e.g. arrays, objects) by reference, not by value.
Now, due to the way how React works, the variables declared inside a component are re-recreated on each render, so non-primitive values inside component scope will always be not equal to themselves. Therefore if such values are supplied as dependencies to useEffect hook, their comparison will always be evaluated as false, causing the callback inside the effect to be run on every render.

Here's a bit more info about comparing by value vs comparing by reference in JS.

Collapse
 
theirongiant profile image
theirongiant

I don't think this or the article are correct. The updateArray function creates a new array (with a different reference) which will get recognised by React and will trigger the useEffect.

I've done a codesandbox here to demonstrate: codesandbox.io/s/eloquent-galois-f...

I've also added a 2nd state variable to show that state isn't regenerated every render - useEffect will correctly run only when state has been changed.

Apologies if I've misread or misunderstood.

Collapse
 
clarity89 profile image
Alex K.

The updateArray function creates a new array (with a different reference) which will get recognised by React and will trigger the useEffect.

Correct, both arrays are created at the same time inside component and they both have different references, even if their values are the same. What I meant in my comment though, is that state dependency is recreated every render, so for example when comparing prevState === state, this comparison will always be false because state object from the previous render has a different reference than current state object.
If, however, you'd pass an object, declared outside of the component, as a dependency to useState, it reference would be kept during renders, and not trigger callback inside useEffect if the object wouldn't change.

Thread Thread
 
theirongiant profile image
theirongiant • Edited

'state' in your example will be the same between renders (as long as it hasn't been changed), useState initialises state to the array in the first render but after that will return the same array until it is changed.

If you look at the console output in my codesandbox example it will log 'test' on the intial render but if you click on the 'Change other' button it will trigger a render but you will see that the useEffect doesn't re-run as useState will return the same initial array.

edit

codesandbox.io/s/react-codesandbox...
If you watch the console as you click the button you'll see the child component re-renders without triggering useEffect, useState ensures that the reference to state is stable between renders.