Effects and essential hooks · Lesson 11 of 21
useEffect
Syncing with the outside world, dependencies, and cleanup.
Rendering must be a pure calculation: props and state in, JSX out. Anything else, like starting a timer, calling an API, changing the page title or subscribing to an event, is a side effect, and it belongs in useEffect. React runs effects after the screen updates.
function Clock() {
const [now, setNow] = useState(new Date())
useEffect(() => {
const id = setInterval(() => setNow(new Date()), 1000)
console.log("timer started")
return () => {
clearInterval(id) // cleanup
console.log("timer stopped")
}
}, []) // [] = run once, after the first render
return <p>{now.toLocaleTimeString()}</p>
}
function App() {
const [show, setShow] = useState(true)
return (
<div>
<button onClick={() => setShow(!show)}>{show ? "Hide" : "Show"} clock</button>
{show && <Clock />}
</div>
)
}| Dependencies | When the effect runs |
|---|---|
no array | after every render |
[] | once, after the first render |
[userId] | first time, and whenever |
The function an effect returns is its cleanup. React calls it before running the effect again, and when the component leaves the page. Press "Hide clock" and watch "timer stopped" in the console. Without cleanup the timer would run forever (a memory leak).
function App() {
const [title, setTitle] = useState("SeaCode")
useEffect(() => {
console.log("syncing title:", title)
document.title = title
}, [title]) // re-run only when title changes
return <input value={title} onChange={(e) => setTitle(e.target.value)} />
}Spot the bug
The counter stops at 1 and never goes further. Which line is the cause?
Exercise
Build a countdown from 3: every 100 ms the number drops by one, and at zero it shows Go! and the interval stops. (The page starts by showing 3.)
The page should show: Go!
function App() {
const [n, setN] = useState(3)
return <h2>{n}</h2>
}Learn more from
Played 0 of 2 games
Sign in to save your progress and earn XP.