React useEffect
Run side effects after render: fetching data, subscriptions, and DOM sync
Overview
useEffect runs after React paints the screen. Use it for side effects that should not run during render—API calls, timers, event listeners, and syncing with non-React libraries. The cleanup function runs before the next effect and on unmount.
Syntax / Usage
import { useEffect, useState } from 'react'
function UserProfile({ userId }) {
const [user, setUser] = useState(null)
// Run when userId changes
useEffect(() => {
let cancelled = false
async function load() {
const res = await fetch(`/api/users/${userId}`)
const data = await res.json()
if (!cancelled) setUser(data)
}
load()
return () => { cancelled = true }
}, [userId])
// Run once on mount
useEffect(() => {
document.title = 'My App'
}, [])
return user ? <p>{user.name}</p> : <p>Loading...</p>
}
Examples
Subscribe to window resize:
useEffect(() => {
const onResize = () => setWidth(window.innerWidth)
window.addEventListener('resize', onResize)
return () => window.removeEventListener('resize', onResize)
}, [])
Debounce a search query:
useEffect(() => {
const id = setTimeout(() => fetchResults(query), 300)
return () => clearTimeout(id)
}, [query])
Common Mistakes
- Missing dependencies causing stale closures—enable ESLint
exhaustive-deps - Fetching in
useEffectwithout abort/cancel on unmount or id change - Using
useEffectfor derived state—compute during render instead - Infinite loops from setting state in an effect without proper dependencies
See Also
use-state use-ref use-callback components