useEffect HookThe useEffect Hook allows you to perform side effects in your functional components.
In React, a "side effect" is any operation that affects something outside the scope of the function being executed. Examples of side effects include:
setTimeout or setInterval.useEffectJust like useState, useEffect is a built-in Hook that you import from React:
import React, { useState, useEffect } from 'react';
The useEffect hook takes two arguments:
useEffect(() => { // Side effect logic goes here }, [dependencies]);
useEffect RunsThe dependency array is incredibly powerful. Depending on how you configure it, you can control exactly when your effect fires.
If you do not provide a dependency array, the effect will run after every single render of the component. This can easily lead to infinite loops if you update state inside the effect!
useEffect(() => { console.log("I run after every single render!"); });
[]If you provide an empty array, the effect will run only once, immediately after the component mounts for the first time. This is the equivalent of componentDidMount in older Class components, making it perfect for initial data fetching.
useEffect(() => { console.log("I only run once when the component mounts!"); // Perfect place to fetch initial data from an API }, []);
[prop, state]If you add variables to the array, the effect will only run when the component mounts AND whenever any of those specific dependencies change between renders.
const [count, setCount] = useState(0);useEffect(() => { // This runs on mount, and whenever 'count' changes. document.title =
You clicked ${count} times; }, [count]); // 'count' is the dependency
Some effects create resources that need to be cleaned up before the component unmounts (leaves the screen) or before the effect runs again. Examples include clearing a timer or removing an event listener to prevent memory leaks.
To clean up an effect, your callback function should return a cleanup function.
import React, { useState, useEffect } from 'react';function Timer() { const [seconds, setSeconds] = useState(0);
useEffect(() => { // Set up the interval const intervalId = setInterval(() => { setSeconds(prev => prev + 1); }, 1000);
<span style="color: #6A9955;">// Return the cleanup function</span> <span style="color: #569CD6;">return</span> () <span style="color: #569CD6;">=></span> { <span style="color: #FF69B4;">clearInterval</span>(<span style="color: #008c8f;">intervalId</span>); <span style="color: #6A9955;">// Cleanup the interval on unmount</span> <span style="color: #FF69B4;">console</span>.<span style="color: #FF69B4;">log</span>(<span style="color: #CE9178;">"Timer cleanup!"</span>); };}, []); // Empty array means this runs once on mount
return <h1>Seconds elapsed: {seconds}</h1>; }
Common Pitfall: The Dependency Array is strict. If your effect uses props or state variables, you must include them in the dependency array. If you omit them, your effect might use stale (outdated) values.
If you want a useEffect block to fetch API data exactly once when the component first loads, how should you structure the dependency array?