Seamless Digital Experience.
Happy Customers.

Digital Experience and Error Monitoring Platform - Zipy

Understanding React useEffect cleanup function

Anom Warbhuvan
~ 8 min read | Published on Jan 24, 2024





TABLE OF CONTENT

Fix bugs faster with Zipy!

  • Session replay
  • Network calls
  • Console Logs
  • Stack traces
  • User identification
Get Started for Free

To understand useEffect clean function, we first need to get some idea about side effects and useEffect hook.As developers, we often face the challenge of managing side effects in our applications. These challenges can be related to pulling information via an API, setting up event listeners, or making any changes to your web page. While these side effects can enhance the functionality of our application, they can also introduce bugs and affect the performance if not properly managed.

To handle these side effects efficiently, one can use the useEffect hook in React. It will allow you to define what should happen when a component mounts or updates. In our useEffect hook guide, you will learn more about how to use this hook effectively.

Every time you create a side effect in useEffect, you would need to use the useEffect cleanup function. Now, let’s dive into React’s useEffect cleanup function and how we can utilize it to manage side effects easily.

What is useEffect cleanup function in React?

When a component that uses the useEffect hook is removed from the screen, the useEffect cleanup function is called. It is responsible for cleaning up any side effects that affect the code. So, it ensures that everything is in order before the component is unmounted. When a component utilizing the useEffect hook gets unmounted, the useEffect cleanup function is triggered. Its role is to clean up any side effects that may impact the code.

Why do we often need a cleanup in React?

When working with React, it's usual to create additional actions like fetching information, setting up countdowns, or attaching event listeners. These side effects can create memory leaks, cause bugs, or make the app slower. By cleaning up these side effects, we can avoid these problems.

There are side effects which stay active even after a component unmounts. This can result in problems  such as slower performance, errors, and issues that we did not expect. To sum up, the useEffect cleanup function is crucial in managing side effects in React components lifecycle. Since you are here, I think you would also like to explore useEffect Hook for React Lifecycle, to understand how to manage side effects in functional components.

When is the useEffect cleanup function called?

useEffect cleanup function can takes place in two incidents:

  1. When a component using the useEffect hook unmounts.
  2. When the dependency array in the useEffect hook changes as it triggers a re-render of the component.

It is used to tidy up any unwanted effects that were created during the component's lifespan, and we can also use it to perform additional cleanup tasks.

Take React debugging to the next level, with AI assistance. Join Zipy!

Get Started for free

Cleaning up with useEffect function

When you use the useEffect hook, you have the option to return a cleanup function. This cleanup function is used to clean up any resources or effects that were created in the hook.  You can clean side effects like fetching data from an API, setting up event listeners, or creating intervals or timeouts. Let’s cover these side effects one by one.

Canceling a fetch request

Every time you retrieve any information via an API in your component, you would mostly want to terminate that request. Especially if the component is removed before the request is finished. This could happen in cases when the user moved to any other tab, or closed the browser. Otherwise, the fetch request will keep running in the background, consuming resources and potentially causing issues in our application.

When we make a fetch request with fetch(), we can cancel it by calling the AbortController method. We can use this method in the cleanup function to avoid memory leaks. This is a built-in Web API that allows us to signal to a fetch request that we want to cancel it.

Using the cleanup function to cancel a fetch request in a React component:

    
// Importing hooks from the React library import { useEffect, useState } from 'react'; // Defining a functional component function MyComponent() { // Initializing a state variabl const [data, setData] = useState(null); // Defining a side effect to fetch data from an API useEffect(() => { // Create an instance of the AbortController API to abort the fetch request const controller = new AbortController(); // Define an asynchronous function to fetch data from the API const fetchData = async () => { try { // Make a GET request to the API and pass the AbortSignal of the controller const response = await fetch('API', { signal: controller.signal }); // Parse the response body as JSON const json = await response.json(); // Set the state variable data and log errors setData(json); } catch (error) { console.error(error); } }; // Call the fetchData function to fetch data from the API fetchData(); return () => { controller.abort(); }; }, []); // Render the data if it is available, otherwise showing a loading message return ( <div> {data ? ( <div> <p>Title: {data.title}</p> <p>Status: {data.status ? 'Yes' : 'No'}</p> </div> ) : ( <p>Loading...</p> )} </div> ); }

Here, we create a new AbortController and pass its signal to the fetch request options. This allows us to cancel the request if the component unmounts. We then return a cleanup function that calls the AbortController's abort method, which cancels the request. Keep in mind that you can replace the URL in the fetch method with any other API endpoint that returns JSON data.

By using the cleanup function in this way, we can promise that our fetch requests are properly canceled when our component unmounts.

Cleaning up timeouts

Before we discuss how to cleanup timeouts, let’s first understand what they are. In JavaScript, the setTimeout function is used to execute a piece of code after a specified amount of time has elapsed.

Timeouts can also be used in cases where you want to delay the execution of some code. For example, you might want to show a success message for a few seconds after a user performs an action before hiding it.

Now, every time you are setting a timeout in a component, you usually want to clear it if the component unmounts before the timeout runs. If the timeout is not cleared, it will lead our application to perform a strange behavior.

To clean up timeouts, we need to use the clearTimeout() method. This method allows us to cancel a timeout before it is executed. We can store the timeout ID in a variable and use it in the cleanup function to clear the timeout.

This code shows how you can use the cleanup function to clean up timeouts in a React component:

    
// import hooks from react import { useEffect, useState } from 'react'; // create a functional component function MyComponent() { const [counter, setCounter] = useState(0); // Using useEffect hook set counter useEffect(() => { const timeoutId = setTimeout(() => { setCounter(counter + 1); }, 3000); //update if dependency array changes again return () => { clearTimeout(timeoutId); }; }, [counter]); return ( <div> <p>Count: {counter}</p> </div> ); }

In the above code, we set a timeout that updates the count state variable after one second. We then return a cleanup function that calls the clearTimeout() method with the timeout ID, which cancels the timeout.

This will help us in ensuring that our timeouts are properly cleaned up before the component gets unmounted. It will also help us in preventing unexpected behavior or errors in our application and improve its overall stability.

Cleaning up intervals

In React's useEffect hook, an interval is a way to repeatedly execute a function after a certain period of time has elapsed. The setInterval function takes two arguments to create an interval, where function is the first argument and time interval is second argument.

The function passed to setInterval will be executed repeatedly at the specified interval until the component unmounts or the interval is cleared with the clearInterval function. It helps in polling a server for updates or periodically updating the UI.

You can refer this code on how to use the cleanup function to clean up intervals in a React component:

    
// import hooks from react import { useEffect, useState } from 'react'; // create a functional component function MyComponent() { const [counter, setCounter] = useState(0); // use the hook to update the counter by 1 useEffect(() => { const intervalNumber = setInterval(() => { setCounter(counter + 1); }, 3000); // if the dependency array changes, hook will run again return () => { clearInterval(intervalNumber); }; }, [counter]); return ( <div> <p>Count: {counter}</p> </div> ); }

In this example, we chose an interval that updates the count state variable every second. The interval is then cancelled by calling the clearInterval() method with the intervalNumber in the cleaning function that we subsequently return.

We can make sure that our intervals are correctly cleaned up when our component unmounts by utilizing the cleaning function in this manner.

Take React debugging to the next level, with AI assistance. Join Zipy!

Get Started for free

Cleaning up event listeners

When the component is removed from the screen, remove the event listener. This will prevent from memory leaks and potential bugs in your application.

The useEffect hook can be used to create an event listener and clean it up when the component is unmounted. To create an event listener using useEffect, you can use the addEventListener method on the window object inside the hook.

For example, let's say you want to create an event listener for the scroll event. You can use the following code:

    
// import the hooks from react import { useState, useEffect } from 'react'; function MyComponent() { const [scrollPosition, setScrollPosition] = useState(0); useEffect(() => { function scrollHandler() { // Update the state with the current scroll position setScrollPosition(window.pageYOffset); } // Add the event listener window.addEventListener('scroll', scrollHandler); // Remove the event listener on cleanup return () => { window.removeEventListener('scroll', scrollHandler); }; }, []); return ( <div> <p>Current scroll position: {scrollPosition}px</p> </div> ); }

In this code, the useEffect hook is used to add an event listener for the scroll event using window.addEventListener. The scrollHandler function is called when the event is triggered.

The second argument to useEffect is an empty array, which means that the hook will only run once, when the component is mounted. This ensures that the event listener is only added once.

The return statement inside the hook is used to clean up the event listener. When the component is unmounted, the function passed to return is called, which removes the event listener using window.removeEventListener.

By using useEffect to create and clean up event listeners, you can ensure that your React application is efficient and bug-free.

Cleaning up WebSockets

When working with WebSocket it is crucial to close the connection before a component unmounts in React application. By doing this, your application's possible flaws and memory leaks are avoided.

When a component is mounted, a WebSocket connection may be established and cleaned up using the useEffect hook. Use the WebSocket API within the hook to establish a WebSocket connection using useEffect.

Now if you plan to connect useWebSocket, you can refer to the code, I have shared here:

    
// import hook from react import { useEffect } from 'react'; // create a functional component function MyComponent() { useEffect(() => { const socket = new WebSocket('ws://localhost:3000'); socket.addEventListener('open', openHandle); socket.addEventListener('message', messageHandle); socket.addEventListener('close', closeHandle); // Clean up the WebSocket connection return () => { socket.removeEventListener('open', openHandle); socket.removeEventListener('message', messageHandle); socket.removeEventListener('close', closeHandle); socket.close(); }; }, []); function handleOpen() { console.log('WebSocket connection opened'); } function handleMessage(event) { console.log('Received data from server:', event.data); } function handleClose(event) { console.log('WebSocket connection closed with code:', event.code); } return ( <div> {/* Your component code here */} </div> ); }

Using the WebSocket API, a WebSocket connection is established in this code using the useEffect hook. The openHandle, messageHandle, and closeHandle functions are responsible for handling events during the communication between the client and server. The openHandle function will successfully connect with the server, whereas the messageHandle function is triggered upon receiving data by the client. Meanwhile, the closeHandle function is invoked upon closing the connection to the server.

The empty array sent as the second parameter to useEffect indicates that the hook should only be used once, when mounting the component. The hook's return clause is used to close the WebSocket connection. When the part of the program related to this feature is no longer in use, the supplied function is executed. This function removes the event listeners using socket.removeEventListener and ends the connection to the server using socket.close.

Using this cleanup function, we can perform critical tasks immediately after the component unmounts.

Take React debugging to the next level, with AI assistance. Join Zipy!

Get Started for free

Conclusion

Understanding the useEffect cleanup function is crucial for properly managing your React components side effects. However, useEffect is just one part of React's complex lifecycle, and it's important to have a solid understanding of the whole picture to create robust and performant applications. We highly recommend you to check out our other blog posts on related topics, such as useEffect Hook for React Lifecycle, useEffect hook guide, and useEffect dependency array.

By mastering these concepts, you can make the most of React's robust programming style and create productive, maintainable, and simple-to-reason apps. We hope this article will be helpful in your journey towards becoming a React expert.

Till then. Happy Coding!

Call to Action

Feel free to comment or write to us in case you have any further questions at support@zipy.ai. We would be happy to help you. In case you want to explore for your app, you can sign up or book a demo.











Fix bugs faster with Zipy!

Get Started for Free
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Want to solve customer bugs even before they're reported?

The unified digital experience platform to drive growth with Product Analytics, Error Tracking, and Session Replay in one.

SOC 2 Type 2
Zipy is GDPR and SOC2 Type II Compliant
© 2023 Zipy Inc. | All rights reserved
with
by folks just like you
// open links in new tab script