useEffect — running side effects
Some work happens "outside" rendering
A component's main job is to return JSX from its props and state. But sometimes you need to do something extra — fetch data, set a timer, save to localStorage, or update the page title. These are called side effects, and React handles them with useEffect.
The basic shape
import { useState, useEffect } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setSeconds((s) => s + 1);
}, 1000);
return () => clearInterval(id); // cleanup
}, []);
return <p>{seconds} seconds passed</p>;
}
useEffect takes a function to run after the component renders.
The dependency array — the key to control
That [] at the end is the dependency array, and it controls when the effect runs:
[](empty) → run once, when the component first appears. (Perfect for loading data.)[count]→ run again whenevercountchanges.- no array → run after every render (rarely what you want).
useEffect(() => {
console.log("count changed to", count);
}, [count]);
Cleanup — tidy up after yourself
If your effect starts something ongoing (a timer, a subscription), return a function to stop it. React runs that cleanup when the component disappears. In the Timer above, return () => clearInterval(id) stops the timer so it does not leak.
Why does useEffect matter?
Because it is how React talks to the outside world — APIs, timers, the browser. The single most common use is loading data when a page opens, which we do next.
useEffect runs side effects after render. The dependency array controls when:
[]= once,[x]= when x changes. Return a cleanup function for timers and subscriptions.