DEV Community

Cover image for When useEffect runs

When useEffect runs

Cassidy Williams on February 10, 2023

useEffect is one of those React/Preact hooks that most people have a love/hate relationship with, but like it or not, it's good to understand how i...
Collapse
 
thethirdrace profile image
Comment hidden by post author
Collapse
 
vanyaxk profile image
Ivan

Great article! Why do useEffects trigger when they use callbacks sent as props from the parent? It does not happen with simple callbacks, like the ones from useState though

Collapse
 
tejasq profile image
Tejas Kumar

It’s because the useEffect does a shallow comparison of the values in its dependency array.

Consider the following scenario:

(() => true) === (() => true)
Enter fullscreen mode Exit fullscreen mode

We’re comparing a function that returns true with another function that returns true. We think they’re the same, but to React, they’re two different functions because they’re both initialized as two distinct functions even though they do the same thing.

If we compare references to functions, then we have equality:

const a = () => true;
const b = () => true;
const c = a;

a === a; // true
a === b; // false
a === c; // true
Enter fullscreen mode Exit fullscreen mode

Comparing references, not values achieves the effect you want.

The callbacks from useState are references.

Another way you can go about this is by wrapping your callbacks in useCallback for even more control.

Collapse
 
vanyaxk profile image
Ivan

Thanks a ton, this explains it!

Thread Thread
 
tejasq profile image
Tejas Kumar

Happy to serve you, Ivan!

Collapse
 
codeofrelevancy profile image
Code of Relevancy

Great article. Thank you for sharing.
The useEffect hook is truly a game-changer, it elegantly combines simplicity and functionality, making it an essential tool for any React developer..

Collapse
 
gene profile image
Gene

Thank you!

Collapse
 
bookercodes profile image
Alex Booker

Brilliant explanation @cassidoo. I love the way you write!

Collapse
 
rishadomar profile image
Rishad Omar

Thanks for this articles and the comments below help my understanding.

Collapse
 
lindiwe09 profile image
Doklin

l value the insights and guidance you provide @cassidoo . l love the way you write.

Collapse
 
shiraze profile image
shiraze

Hi, I'm pretty sure the example with let isCurrent = true is incorrect, as isCurrent will be set to true each time the useEffect is fired (after initial render, and whenever uid updates), so will mean that setUser() will be called at each of these times. You could make use of useRef() to make sure it's only called initially, or use the empty dependency array.

Collapse
 
cassidoo profile image
Cassidy Williams

It depends on the fetch timing! If fetch is particularly slow and the uid changes, then the isCurrent will be false for that original fetch call. The functions in useEffect are called in a stack of sorts, with a new isCurrent variable for each one.

Collapse
 
shiraze profile image
shiraze

I thought the fetch promise behaves similar to an enclosure (i.e. the value of inner vars are based on the value of outer vars at the time the function/promise is defined), so I created this codepen to check behaviour: codepen.io/ambience/pen/PodYBqa

You are correct @cassidoo, and we can see from the codepen that if multiple clicks on the button to update uid is made in quick succession, only the last click results in the setUser call being made.

Collapse
 
rei7 profile image
rei

everyone, before you use "ref flag" to bypass react 18+ strict mode running twice, you should know it's actually designed to be a beneficial FEATURE to help catch bugs and find problems. React docs goes to great length talking about it.

Some comments have been hidden by the post's author - find out more