React useEffect Explained: When You Actually Need It

useEffect synchronizes a React component with systems outside React, like timers, network requests, or the browser DOM. Learn when to use it and when to skip it.

6 min read

The useEffect Hook is how a React component synchronizes with systems outside React. It runs a function after React commits the UI to the screen, which makes it the right place for timers, network requests, browser APIs, and third-party widgets. If no external system is involved, you usually do not need this Hook at all.

What useEffect does

Rendering must stay pure. A component takes props and state, calculates the JSX it should show, and returns it without changing anything outside itself. Starting a timer or connecting to a server is a side effect, so that work cannot happen during rendering.

The useEffect Hook moves that work to a later moment. React updates the screen first, then runs the function you passed in. That function is called the setup, and it can return a cleanup function that undoes whatever the setup started.

Effect setup and cleanup run as a pair

The diagram shows the contract behind every Effect. Setup starts the synchronization, and cleanup stops it.

React runs setup after mount and again after every dependency change. It runs cleanup before each new setup and once more when the component unmounts.

A first example

A clock is the smallest useful case. The external system here is the browser timer, which keeps ticking no matter what your component does.

App.jsxApp.jsx
import { useEffect, useState } from "react";
 
function Clock() {
  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const id = setInterval(() => setTime(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
 
  return <p>{time.toLocaleTimeString()}</p>;
}

While the component is on screen, the page shows the current time and updates it every second. The setup creates an interval, and the cleanup clears it, so a stale timer never keeps running after the component leaves the screen. The empty array at the end tells React to run this setup only once, which is exactly what a clock needs.

When you actually need an Effect

Use the Hook when the component must stay synchronized with something React does not control. The classic cases all share one shape: a start action and a matching stop action.

  • A timer created with setInterval or setTimeout.
  • A subscription added with addEventListener or an external store.
  • A network request that must follow the current props or state.
  • A third-party widget with imperative methods such as play and pause.

Without the Hook, none of these have a clean place to live. Rendering cannot start a timer, and an event handler does not run when the component first appears.

Effects are the right fit here because the work is caused by the component appearing, not by one specific click. Every one of these pairs a start with a stop. Cleaning up timers, listeners, and subscriptions walks through that pairing with small working examples.

When you do not need an Effect

Two common cases need no Effect at all. If a value can be calculated from props or state, calculate it during render. If code should run because the user clicked a button, keep it in the event handler.

App.jsxApp.jsx
const fullName = `${firstName} ${lastName}`;

A full name is derived from two existing values, so it belongs in the render body, not in state and not in an Effect. See common patterns that let you avoid an Effect for a longer tour of these cases.

Setup and cleanup under Strict Mode

In development, Strict Mode mounts, unmounts, and remounts each component once. React therefore runs setup, then cleanup, then setup again on the first mount.

This is a stress test, not a bug, and it never happens in the production build. If the double run breaks something, the cleanup function is missing a step.

What to learn next

The second argument to the Hook controls when setup runs again. Continue with how the dependency array works.

Rune AI

Rune AI

Key Insights

  • useEffect runs after React commits the UI and is for external synchronization.
  • Setup runs on mount and after dependency changes; cleanup runs before each re-sync and unmount.
  • Skip the Hook when a value can be derived during render or logic belongs in an event handler.
  • Strict Mode runs one extra setup and cleanup cycle in development only.
RunePowered by Rune AI

Frequently Asked Questions

When does useEffect run?

It runs after React commits the component output to the screen. React also runs the cleanup function before each new setup and before unmount.

What is an external system in React?

Anything React does not control, such as a timer, a network request, a browser API, a subscription, or a third-party widget.

Do I always need useEffect to fetch data?

No. You can fetch in an Effect, but frameworks and data libraries offer built-in fetching that handles caching, errors, and server rendering more efficiently.

Conclusion

useEffect is React's escape hatch for synchronizing a component with an outside system. Use it for timers, subscriptions, browser APIs, and network requests, and skip it whenever a value can be computed during render or belongs in an event handler.