What is the UseEffect hook in React?
The useEffect
hook in React allows you to perform side effects in functional components. A side effect can be anything that affects something outside of the component, such as data fetching, subscriptions, timers, or manually manipulating the DOM.
How useEffect
Works
The useEffect
hook takes two parameters:
- A function that contains the side effect code.
- An optional dependency array that tells React when to run the effect.
Here’s the basic syntax for useEffect
:
useEffect(() => {
// Side effect code here
return () => {
// Cleanup code here (optional)
};
}, [dependencies]);
- Effect function: The first argument is a function where you put your side-effect code. This function runs after the component renders.
- Cleanup function: If you return a function from the effect, React treats it as a cleanup function, which runs before the effect re-runs or when the component unmounts.
- Dependency array: The second argument is an array of dependencies that tells React when to run the effect. If dependencies change, the effect re-runs. If you omit this array, the effect will run after every render.
Example: Using useEffect
for Data Fetching
Here’s a simple example of fetching data when a component mounts.
import React, { useState, useEffect } from "react";
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
// Side effect: fetch data
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => setData(data))
.catch(error => console.error("Error fetching data:", error));
}, []); // Empty dependency array: run effect only once on mount
return (
<div>
{data ? <p>Data: {JSON.stringify(data)}</p> : <p>Loading...</p>}
</div>
);
}
In this example:
- We use
useEffect
with an empty dependency array[]
, so the effect runs only once when the component mounts. - The effect fetches data when the component mounts, and
setData
updates the state when the data is loaded. - The component re-renders with the fetched data once it’s available.
Dependencies in useEffect
The dependency array controls when the effect re-runs. Here are a few key scenarios:
- No Dependency Array:
useEffect(() => { ... });
- The effect will run after every render (initial and subsequent renders).
- Empty Dependency Array:
useEffect(() => { ... }, []);
- The effect will run only once, when the component mounts, similar to
componentDidMount
.
- The effect will run only once, when the component mounts, similar to
- With Dependencies:
useEffect(() => { ... }, [dependency]);
- The effect will run only when the specified dependencies change.
Example with Dependency Array
function Counter({ count }) {
useEffect(() => {
console.log(`Count changed to ${count}`);
}, [count]); // Effect re-runs only when `count` changes
return <p>Count: {count}</p>;
}
In this example, the effect will only run when the count
prop changes. This is useful for responding to specific changes without re-running the effect on every render.
Cleanup in useEffect
If your effect requires cleanup (e.g., removing event listeners, canceling timers, or unsubscribing from services), you can return a function inside the effect. This cleanup function runs either when the component unmounts or before the effect re-runs.
Example with Cleanup Function
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// Set up a timer
const intervalId = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1);
}, 1000);
// Cleanup function to clear the timer
return () => clearInterval(intervalId);
}, []); // Empty dependency array: runs only on mount and unmount
return <p>Elapsed time: {seconds} seconds</p>;
}
In this example:
setInterval
creates a timer that updates theseconds
state every second.- The cleanup function
clearInterval(intervalId)
stops the timer when the component unmounts, preventing memory leaks.
Summary
useEffect
allows you to perform side effects in functional components, such as data fetching, timers, and event listeners.- It runs after the component renders and can re-run if dependencies change.
- You can control when
useEffect
runs by providing a dependency array:- No dependencies: Runs after every render.
- Empty array
[]
: Runs only once on mount. - Specified dependencies
[dep1, dep2]
: Runs when any of these dependencies change.
- The optional cleanup function handles tasks like clearing timers, unsubscribing, and removing event listeners.
When to Use useEffect
- Data fetching (e.g., calling APIs or fetching resources).
- Subscribing and unsubscribing (e.g., event listeners, WebSocket connections).
- Timers and intervals (e.g., countdowns, animations).
- DOM manipulation (e.g., focus, scroll position) – although this should be done sparingly in React.
By managing side effects with useEffect
, you ensure that your React components stay reactive to changes, update as needed, and clean up resources efficiently, keeping the component lifecycle predictable and efficient.