Side Effects with useEffect
useEffect runs code after render to sync with things outside React.
Syntax
useEffect(() => {
// effect
return () => { /* cleanup */ };
}, [deps]);useEffect lets you run side effects — things outside React's rendering, like subscriptions, timers, or manually touching the DOM — after the component renders.
Dependencies & cleanup
- The dependency array controls when the effect re-runs:
[]runs once on mount;[a, b]re-runs whenaorbchange. - Return a cleanup function to undo the effect (clear a timer, remove a listener). React runs it before the next effect and on unmount.
Example
import { useState, useEffect } from 'react';
function Clock() {
const [now, setNow] = useState(new Date());
useEffect(() => {
const id = setInterval(() => setNow(new Date()), 1000);
return () => clearInterval(id); // cleanup
}, []);
return <p>{now.toLocaleTimeString()}</p>;
}When to use it
- A user profile page fetches account data with useEffect after mounting and cancels the in-flight request with an AbortController if the user navigates away before it completes.
- A chat component subscribes to a WebSocket inside useEffect and returns a cleanup function that closes the connection when the component unmounts.
- A document-title manager uses useEffect with a dependency on the page name so the browser tab title always reflects the currently viewed section.
More examples
Fetch data on mount
Fetches data after render, re-runs when userId changes, and cleans up with AbortController on unmount or re-run.
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
const controller = new AbortController();
fetch(`/api/users/${userId}`, { signal: controller.signal })
.then(r => r.json())
.then(setUser)
.catch(() => {});
return () => controller.abort();
}, [userId]);
if (!user) return <p>Loading...</p>;
return <h2>{user.name}</h2>;
}Sync document title
Updates the browser tab title whenever the title prop changes and restores the previous title on cleanup.
import { useEffect } from 'react';
function PageTitle({ title }) {
useEffect(() => {
const previous = document.title;
document.title = `${title} | MyApp`;
return () => { document.title = previous; };
}, [title]);
return null;
}Subscribe and clean up
Subscribes to browser network events in useEffect and removes them in the cleanup to prevent memory leaks.
import { useState, useEffect } from 'react';
function OnlineStatus() {
const [online, setOnline] = useState(navigator.onLine);
useEffect(() => {
const handleOnline = () => setOnline(true);
const handleOffline = () => setOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return <p>{online ? 'Online' : 'Offline'}</p>;
}
Discussion