React provides several built-in Hooks that help us manage different aspects of a component. One of the most commonly used Hooks is useEffect. It is mainly used to perform side effects in a React component.
What is useEffect?
useEffect is a React Hook that allows us to perform an operation after a component renders.
The basic syntax is:
useEffect(() => {
// side effect code
});
To use useEffect, we need to import it from React:
import { useEffect } from "react";
What is a Side Effect?
A side effect is an operation that happens outside the normal process of calculating and returning the UI.
Common examples include:
- Fetching data from an API
- Updating
localStorage - Setting a timer
- Adding event listeners
- Updating the browser document title
- Subscribing to external services
For example:
useEffect(() => {
document.title = "My React App";
});
Here, changing the browser tab title is a side effect.
Dependency Array
The dependency array controls when the effect should run.
1. Without a Dependency Array
useEffect(() => {
console.log("Effect executed");
});
When there is no dependency array, the effect runs after every render.
2. Empty Dependency Array
useEffect(() => {
console.log("Effect executed");
}, []);
An empty dependency array means the effect runs after the initial render. This is commonly used for operations that need to happen when a component starts.
3. With Dependencies
useEffect(() => {
console.log("Count changed");
}, [count]);
Here, count is a dependency. The effect runs after the initial render and again when the value of count changes.
Multiple dependencies can also be used:
useEffect(() => {
console.log("Effect executed");
}, [count, name]);
The effect can run when either count or name changes.
useState and useEffect
useEffect is frequently used together with useState.
import { useState, useEffect } from "react";
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Count:", count);
}, [count]);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
</div>
);
}
When the button is clicked, count changes. React re-renders the component, and because count is a dependency, the effect runs again.
The basic flow is:
State changes
↓
React re-renders
↓
UI updates
↓
useEffect runs
Cleanup Function
Some effects create resources that need to be stopped or removed. For example, timers and event listeners.
useEffect allows us to return a cleanup function:
useEffect(() => {
const timer = setInterval(() => {
console.log("Running...");
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
The cleanup function helps prevent unnecessary timers, listeners, or subscriptions from continuing after they are no longer needed.
Real-World Example
A common example is saving data to localStorage.
useEffect(() => {
localStorage.setItem("tasks", JSON.stringify(tasks));
}, [tasks]);
Whenever the tasks state changes, the latest tasks are stored in localStorage.
Important Rules to Remember
There are three important patterns to remember:
// 1. No dependency array
useEffect(() => {});
Runs after every render.
// 2. Empty dependency array
useEffect(() => {}, []);
Runs after the initial render.
// 3. Dependency array
useEffect(() => {}, [count]);
Runs after the initial render and when count changes.
Conclusion
useEffect is an important React Hook for handling side effects. It is especially useful when working with APIs, timers, localStorage, event listeners, subscriptions, and other external operations.
The easiest way to understand useEffect is to remember:
Effect = What should happen?
Dependency array = When should it happen?
Once you understand the dependency array and cleanup function, you have a strong foundation for using useEffect in real React applications.
Top comments (0)