DEV Community

Umang Mittal
Umang Mittal

Posted on

1

useEffect: The Hook That Keeps You Guessing (And Refreshing)

Hi my developer community!

Let's be honest, useEffect is one the most used hook in the React Eco-system. We all have at some point in our development life used this hook for running some side-effects.

Let's learn some advanced things about the useEffect.

We all know that useEffect is used to trigger any side-effect in your React component.

The syntax of useEffect is:

import { useEffect } from 'react';

useEffect(callbackFn, dependencyArr)
Enter fullscreen mode Exit fullscreen mode

Dependency Array

Well, in my experience in taking interviews I asked this question a lot. What would happen if I don't pass any value in the second argument of the useEffect?

And mostly candidates say, "The callback function will run infinitely". That is not the correct answer. And it also shows how much experience they have with the useEffect hook.

Let's try doing that.

Image description

I have one console log in the component's useEffect and one outside of the effect. Notice that there is not dependency array in the useEffect hook.

And here is the output:
Image description

As you can see there is no infinite logs. That means useEffect hook only runs on every render when there is no dependency array.

Cleanup Function

Sometimes, we attach an event listener on the mount of a component. But have you wondered what happens when the component unmounts. Does that event listener gets destroyed?

To demonstrate, let's attach a keyup listener on the mount of child component and unmounts the child component after 3 seconds.

Image description

CAUTION: For demonstration purpose, I have removed the Strict Mode provided in React to demonstrate the deployed version of outputs.

Image description

Now, even after the child component unmounts, the event listener is still active and I can still see the logs when I press any key. That proves the fact that event listeners will still mount even when the component itself unmount.

To resolve this we have a cleanup function in useEffect. This will run before the callbackFn and on unmount of the component (I know sounds confusing but I will explain).

Some Dev's say it will run only when the component unmounts which is not entirely true. According to React dev docs:
React calls your setup and cleanup functions whenever it’s necessary, which may happen multiple times:

1. Your setup code runs when your component is added to the page (mounts).
2. After every re-render of your component where the dependencies have changed:
    - First, your cleanup code runs with the old props and state.
    - Then, your setup code runs with the new props and state.
    - Your cleanup code runs one final time after your component is removed from the page (unmounts).
Enter fullscreen mode Exit fullscreen mode

So, if you have given some dependencies in the dependencyArr, then the cleanup function is called before it runs the side-effect again and in case of empty dependency array it will run on unmount.

Order - Order

Now the basic things out of the way, let's understand the execution order of useEffect in a Parent-Child relationship.

Image description

In this code, as you can see we have console logs out of the useEffect and inside useEffects as well. So, try to solve it without looking at the solution.
Note: I have disabled React.StrictMode to make the console look cleaner, but if won't make any difference in the order of execution.

The answer:

Image description

Hmm.., If you think the Parent's useEffect should've run first, here you got the answer.

Why??
React prioritizes effects in the child components before the parent to ensure that effects affecting the child’s layout or behavior are handled first. This helps to avoid potential issues like the parent reacting to changes in the child that have not yet been fully applied.

And what would be the order of the cleanup functions, is it the same or different?
Let's tweak our little example to see the result:

Image description

So, Now we have two useEffect's in both the components. I introduced a count variable just to re-render the parent and child and passed that as a prop to child component.

And yes, the order of the useEffects being registered also matters. If both the side-effects needs to run, the one that registers first will run first.

Let's see what would be the execution of this. As an exercise, you can think of a solution first before looking at the console.

Image description

what we've understood so far seems to be working here as well. First we have both parent's and child's outer console's and then useEffect console's. Child's first and then parent's.

Now, let's see what happens when you update the state. In our case, clicking on the button.

I am going to put a console log "Button clicking event" to segregate the output of before the button clicked and after the button is clicked.

Image description

As you can see, Parent and child render comes first.
Next up is the cleanup functions. And yes, in the reverse order again.
After the cleanup functions, we again have the side-effects running similarly.

Note: For the simplicity, I've removed the React.StrictMode

I guess that's it for the post, I hope you have gained some extra knowledge of how React works by attaching events and the order of execution for useEffect by reading this post.

Thanks for reading, I'll code a bug next time.
That's Umang, signing off.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More