Mastering useEffect in React.js: A Comprehensive Guide

Olga Green
5 min readJul 27, 2023

--

In React.js, managing side effects, such as fetching data, subscriptions, and manipulating the DOM, is a crucial aspect of building modern and dynamic web applications. The useEffect hook plays a central role in handling side effects and lifecycle events in functional components. Understanding how to use useEffect effectively is essential for writing clean, efficient, and bug-free React code.

In this comprehensive blog post, we will dive deep into the world of useEffect in React js. We will explore its purpose, syntax, best practices, and various use cases. From simple data fetching to handling cleanup and optimizations, we'll cover everything you need to know to become a useEffect expert.

react
Photo by Damian Zaleski

What is the useEffect hook?

useEffect is one of the most fundamental hooks in React js, introduced in React 16.8. It allows functional components to perform side effects, such as data fetching, subscriptions, or DOM manipulations, after rendering. With useEffect, developers can perform side effects without writing class components and managing lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount.

Why is useEffect important?

useEffect is crucial for handling side effects and asynchronous operations in React.js applications. It helps keep components more declarative and composable, simplifying the overall codebase and making it easier to reason about side effects.

Understanding the useEffect syntax

The useEffect hook takes two arguments: a callback function and an optional dependency array. The callback function represents the side effect logic, while the dependency array controls when the side effect should run or update.

import React, { useEffect } from 'react';
function ExampleComponent() {
useEffect(() => {
// Side effect logic goes here
return () => {
// Cleanup logic goes here (optional)
};
}, [/* Dependency array */]);
return <div>Example Component</div>;
}

How to Use useEffect?

Implementing basic side effects

To perform a basic side effect, such as updating the document title, you can use useEffect without a dependency array. The side effect will run after every render.

import React, { useEffect } from 'react';
function TitleUpdater() {
useEffect(() => {
document.title = 'Updated Title';
});
return <div>Component with Updated Title</div>;
}

Dependencies and reactivity

The dependency array in useEffect specifies which values the effect depends on. When the values in the dependency array change, the effect will re-run. Omitting the dependency array or passing an empty array will cause the effect to run only once (on mount) and not re-run for subsequent renders.

import React, { useEffect, useState } from 'react';
function DependencyExample() {
const [count, setCount] = useState(0);
useEffect(() => {
// This effect will re-run whenever `count` changes
document.title = `Count: ${count}`;
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

Cleanup with useEffect

useEffect can also return a cleanup function to handle the cleanup of resources when the component is unmounted or before the effect runs again. This is particularly useful for subscriptions, event listeners, or timers that need to be cleared when the component is no longer in the DOM.

import React, { useEffect, useState } from 'react';
function SubscriptionExample() {
const [subscription, setSubscription] = useState(null);
useEffect(() => {
const subscription = subscribeToExternalService();
setSubscription(subscription);
return () => {
// Cleanup function will unsubscribe when the component is unmounted
subscription.unsubscribe();
};
}, []);
return <div>Component with Subscription</div>;
}

Common Use Cases of useEffect

Data fetching with useEffect

One of the most common use cases of useEffect is fetching data from an API. By performing data fetching inside useEffect, you can avoid infinite loops and ensure the data is fetched only when necessary.

import React, { useEffect, useState } from 'react';
function DataFetchingExample() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => setData(data))
.catch((error) => console.error(error));
}, []);
return (
<div>
{data.map((item) => (
<p key={item.id}>{item.name}</p>
))}
</div>
);
}

Subscriptions and event listeners

useEffect is ideal for managing subscriptions and event listeners. When subscribing to external data sources or setting up event listeners, the cleanup function ensures that the subscriptions are properly removed when the component is unmounted.

import React, { useEffect, useState } from 'react';
function EventListenerExample() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMouseMove = (event) => {
setMousePosition({ x: event.clientX, y: event.clientY });
};
document.addEventListener('mousemove', handleMouseMove);
return () => {
// Cleanup function will remove the event listener when the component is unmounted
document.removeEventListener('mousemove', handleMouseMove);
};
}, []);
return (
<div>
<p>Mouse Position: {mousePosition.x}, {mousePosition.y}</p>
</div>
);
}

Animations and DOM manipulations

When working with animations or manipulating the DOM, useEffect can be used to handle side effects like starting or stopping animations, updating CSS classes, or adjusting layout properties.

import React, { useEffect, useRef } from 'react';
function AnimationExample() {
const boxRef = useRef(null);
useEffect(() => {
// Start an animation when the component mounts
boxRef.current.style.animationPlayState = 'running';
return () => {
// Cleanup function will stop the animation when the component is unmounted
boxRef.current.style.animationPlayState = 'paused';
};
}, []);
return (
<div>
<div ref={boxRef} className="box"></div>
</div>
);
}

Timer and interval functions

useEffect is useful for handling timers and intervals in React components. The cleanup function ensures that timers are cleared to prevent memory leaks.

import React, { useEffect, useState } from 'react';
function TimerExample() {
const [timer, setTimer] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setTimer((prevTimer) => prevTimer + 1);
}, 1000);
return () => {
// Cleanup function will clear the interval when the component is unmounted
clearInterval(interval);
};
}, []);
return (
<div>
<p>Timer: {timer} seconds</p>
</div>
);
}

useEffect Optimizations

Preventing unnecessary re-renders

To avoid unnecessary re-renders of the component, ensure that the dependencies in the dependency array are properly set. The effect will re-run only when the values in the dependency array change.

import React, { useEffect, useState } from 'react';
function OptimizeExample() {
const [count, setCount] = useState(0);
useEffect(() => {
// This effect will re-run only when `count` changes
document.title = `Count: ${count}`;
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

Debouncing and throttling side effects

Debouncing and throttling are techniques used to control the frequency of side effects, such as data fetching or handling user input. By debouncing or throttling the effect, you can reduce the number of times the effect runs and optimize performance.

Conclusion

In conclusion, the useEffect hook is a powerful and essential tool in the React.js developer toolkit. It enables functional components to handle side effects, such as data fetching, subscriptions, and DOM manipulations, in a clean and efficient manner. By understanding the different use cases, best practices, and optimizations of useEffect, developers can build more reliable, performant, and maintainable React.js applications.

Throughout this blog post, we have explored the various aspects of useEffect, including its syntax, dependency management, cleanup mechanisms, and common use cases. We have also delved into performance optimizations, testing strategies, and real-world applications of useEffect. By mastering useEffect, developers can enhance their productivity and create dynamic and interactive user experiences with React.js.

Choosing CronJ as your development partner ensures access to cutting-edge technology, adherence to best practices, and a commitment to delivering successful outcomes. For all your React.js and web development needs, CronJ react js software development company is the right choice to achieve excellence.

References

  1. https://dev.to/t/react
  2. difference between usestate and useeffect
  3. Browser DOM vs Virtual DOM
  4. Node js vs React js
  5. In-App Purchase in React Native: A Comprehensive Guide | by Olga Green | Jul, 2023 | Medium

--

--

Olga Green

Hello! I’m Olga Green. My design practice combines design thinking, user research and experience strategy.