Do cleanup from useEffect in React.js whenever possible

Amit Merchant · June 28, 2022 ·

The useEffect hook in React.js is the one that you would be using to run side effects for a particular component.

There’s a little issue with it though.

The problem

For instance, if you want to run some side-effects only once every time a component renders (or in other words when the component mounts), here’s how you can do it.

useEffect(() => {
  // This runs only on mount (when the component appears)
}, []);

As you can tell, you would leave the dependency array empty in this case, and now anything inside this useEffect would run only once every render.

This should work fine but consider the following scenario where you would render a dialog when the component renders.

Here’s how this would look like.

useEffect(() => {
    const dialog = dialogRef.current;
    dialog.showModal();
}, []);

You may think that this would work perfectly fine but let’s think about a situation where let’s say your app is a single-page application (SPA) and you navigate to the other page while the dialog is still open and come back once again to the same page.

In this case, the above useEffect would run again and the <dialog> element would throw an error since the previous instance of the dialog is still open.

The cleanup function

To mitigate this, we can write a cleanup function in this useEffect that closes the dialog instance.

Here’s how that would look like.

useEffect(() => {
    const dialog = dialogRef.current;
    dialog.showModal();

    // the cleanup function
    return () => dialog.close();
}, []);

The explanation

Since the cleanup function would run before running the actual useEffect logic, it would first close the initial dialog instance and open a new instance of the dialog in situations where the useEffect would run multiple times as I discussed previously.

Here’s the sequence of how things run.

  • The <dialog> is opened
  • The <dialog> is closed through the cleanup function when useEffect runs again
  • The <dialog> is opened afterward

Lastly, the cleanup function would run once again when the component unmounts (gets removed).

In closing

As you can tell, to prevent issues like this from arising, it’s always advisable to use the useEffect hook with a cleanup function that would possibly negate the useEffect upon remounting the component.

👋 Hi there! I'm Amit. I write articles about all things web development. If you like what I write and want me to continue doing the same, I would like you buy me some coffees. I'd highly appreciate that. Cheers!

Comments?