What is useEffect hook?
The `useEffect` hook in React allows you to perform side effects in functional components. Side effects are operations that interact with the outside world or have an impact beyond the component's immediate rendering, such as data fetching, subscriptions, or manually changing the DOM.
What is useEffect?
useEffect runs after every render of the component (by default). It takes a function as its first argument, which is the effect to be performed. This function is where you place your imperative code that interacts with an external system or performs a side operation.
Common Use Cases
- Data fetching from an API.
- Setting up subscriptions or event listeners (e.g., to a WebSocket or browser events).
- Manually changing the DOM (e.g., focusing an input, interacting with a third-party library).
- Timers (e.g.,
setTimeout,setInterval). - Logging.
Basic Syntax
import React, { useEffect } => useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// This effect runs after every render
console.log('Component rendered or count changed:', count);
});
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
The Dependencies Array
The second argument to useEffect is an optional array of dependencies. This array tells React when to re-run the effect. If any value in the array changes between renders, the effect will re-run. If the array is empty, the effect will run only once after the initial render and never again on subsequent renders.
- No dependencies array: The effect runs after every render.
- Empty dependencies array
[]: The effect runs once after the initial render. This is useful for setup logic that doesn't need to re-run. - Dependencies array
[dep1, dep2]: The effect runs after the initial render and wheneverdep1ordep2changes.
import React, { useEffect, useState } from 'react';
function MyComponentWithDependencies() {
const [userId, setUserId] = useState(1);
const [data, setData] = useState(null);
useEffect(() => {
// This effect runs when userId changes (or initially)
console.log(`Fetching data for user: ${userId}`);
fetch(`https://api.example.com/users/${userId}`)
.then(response => response.json())
.then(json => setData(json));
// Cleanup function can be returned here if needed
return () => {
console.log(`Cleaning up for user: ${userId}`);
};
}, [userId]); // Effect re-runs if userId changes
return (
<div>
<p>User ID: {userId}</p>
<button onClick={() => setUserId(userId + 1)}>Next User</button>
{data && <pre>{JSON.stringify(data, null, 2)}</pre>}
</div>
);
}
Cleanup Function
Some effects require a cleanup to prevent memory leaks or unwanted behavior (e.g., unsubscribing from a subscription, clearing timers). You can return a function from your useEffect callback, which React will execute when the component unmounts, or before the effect re-runs due to a dependency change.
import React, { useEffect, useState } from 'react';
function EventListenerComponent() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// Cleanup function
return () => {
window.removeEventListener('resize', handleResize);
console.log('Event listener removed.');
};
}, []); // Empty array means this effect runs once and cleans up on unmount
return <p>Window Width: {width}</p>;
}
When to Use and When Not to Use
| Use When | Don't Use When |
|---|---|
| Synchronizing with external systems (APIs, browser events, third-party libraries). | Transforming data purely for rendering (use `useMemo` or direct computation). |
| Performing operations that need to run after every render or only on specific dependency changes. | For every single component render without a specific side effect (manage dependencies carefully). |
| Setting up global state or subscriptions. | Modifying component's state directly based on a previous render (prefer `useState`'s updater function or `useReducer`). |