What are side effects?
React components have one job: return JSX based on props and state. Anything else — fetching data, updating the document title, setting up a timer — is a side effect. It’s something that happens outside the render cycle.useEffect is the hook for running side effects. In this course, you’ll use it mostly for fetching data and syncing with browser APIs (like document title or timers).
Python mental model: your component function is like a function React may call many times to calculate UI. Keep that part “pure” (return JSX from props/state).
useEffect is where you register code that should run after render to sync with the outside world (network, browser APIs, timers).Basic useEffect
useEffect takes two arguments:
- A function — the code to run (the effect)
- A dependency array — when to re-run it
The dependency array
The dependency array controls when the effect runs:In development,
React.StrictMode may run mount effects twice to help reveal bugs. For a simple useEffect(..., []) data-fetch example, that can mean two requests in development unless you guard against it. Production does not do the extra development check.Fetching data on mount
This is the pattern you’ll use most often — load data when a component first appears:Notice the async function is defined inside the useEffect callback, not as the callback itself. This is because useEffect callbacks can’t be async directly — they need to return either nothing or a cleanup function.
Fetching based on a prop or state value
When the data depends on a value (like a user ID from the URL), include it in the dependency array:userId changes (e.g., navigating from one user profile to another), the effect runs again and fetches the new user.
Other common side effects
Updating the document title
Setting up a timer
Cleanup function
The function you return from useEffect runs when the component unmounts (disappears) or before the effect re-runs:- Clearing timers (
clearInterval,clearTimeout) - Closing WebSocket connections
- Cancelling pending requests
- Removing event listeners
Common mistakes
Missing dependency array — infinite loop
Missing dependency array — infinite loop
Making useEffect callback async directly
Making useEffect callback async directly
Object or array as dependency (re-runs every render)
Object or array as dependency (re-runs every render)
The useEffect mental model
Think of useEffect in terms of synchronization, not lifecycle:useEffect(fn, [])— synchronize with nothing (run once)useEffect(fn, [userId])— synchronize with userId (re-run when it changes)useEffect(fn, [a, b])— synchronize with a and b
Also remember:
useEffect callbacks are closures. They capture values from the render where they were created. That’s why missing a dependency can make an effect use an old value (“stale closure”).What’s next?
You can fetch data and manage side effects. Now let’s learn how to conditionally show different UI based on that data — loading spinners, error messages, and content.Conditional rendering
Show different UI based on state and conditions