Side Effects with useEffect
The useEffect hook lets you perform side effects in functional components — things like fetching data, setting up subscriptions, or manually changing the DOM. It runs after React renders the component.
The dependency array controls when the effect runs: no array means every render, empty array means mount only, and specific values mean it runs when those values change.
Example
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// Runs when userId changes
useEffect(() => {
setLoading(true);
fetch(`https://api.example.com/users/${userId}`)
.then(res => res.json())
.then(data => {
setUser(data);
setLoading(false);
});
}, [userId]);
// Runs once on mount
useEffect(() => {
document.title = 'User Profile';
}, []);
// Cleanup example (runs on unmount)
useEffect(() => {
const timer = setInterval(() => console.log('tick'), 1000);
return () => clearInterval(timer); // Cleanup
}, []);
if (loading) return <p>Loading...</p>;
return <h1>{user?.name}</h1>;
} - useEffect(() => {}) — Runs after every render
- useEffect(() => {}, []) — Runs once on mount
- useEffect(() => {}, [dep]) — Runs when dep changes
- Return a cleanup function to run on unmount or before re-running
- Common uses: data fetching, event listeners, timers, DOM updates
Notes
- Always include all variables used inside useEffect in the dependency array. Missing dependencies can cause stale data bugs.
