loading...

Common mistake done while using react hooks

KaRthick on October 11, 2019

Hi all , Many people started using react-hooks including me . The most common issue people face while using hook is infinite loop To avoid such... [Read Full]
markdown guide
 

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.

 

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.

 

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.

'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.

 

This is not very accurate. If you read this article, read through all of the comments. The author has confused most of what he is talking about.

@karthick3018 , you should probably delete this article or make changes after reading through and understanding the comments. This will lead to confusion in the future for other developers.

 

Hi I didn't propose any wrong solution for the problem , I'm just telling don't do this mistake while using react-hooks . If this problem is wrong provide an working demo i'll remove the post

 

Supplying a brand new array will definitely call the hook. The issue is if you maintain the same array, what the hook is fired based on is changed identity. So if you create a new object / array then the hook will fire. If you don't and merely update it, it won't. It's not a react hooks issue. It's is entirely based on Javascript identity. See reference vs value types.

again i'm trying to address an issue based on the scenario where an value in the object gets updated hooks will be called again even the previous value in the object and the current updated value are same

You are creating a new array. This code is simply wrong and misleading. If you want to update the value of name for record 2, find the object in the array, update and set state to the same array. Then your code will make sense.

 

I think that your article would be greatly improved if you suggested a solution or two to the problem you present.
Just my two pennies.

 
code of conduct - report abuse