Skip to content

React Tutorial React Hooks

The useEffect Hook: Side Effects in React

Lesson 60 of 156 2 min read By Deepak Paswan Updated Oct 10, 2026

Runnable lesson · press Try it on the examples to edit and run them here.

Rendering should only calculate JSX from props and state. But apps also need to do other things: set the page title, start a timer, talk to a server, subscribe to something. Those things are side effects, and useEffect is the hook for them.

The syntax

App.jsx
JSX
useEffect(() => {
  // the effect: runs after React has updated the screen
  return () => {
    // optional cleanup: runs before the next effect and when the component is removed
  };
}, [dependencies]);

Your first effect: the document title

App.jsx
JSX
function App() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

After each render where count changed, React runs the effect and updates document.title. (In the playground it changes the title of the preview frame, which you cannot see. In a real project, watch the browser tab.)

When does it run?

  1. React renders your component and updates the screen.
  2. Then, after painting, React runs the effect.

So the effect always sees the committed result of that render. If you need to measure or change the layout before the browser paints, there is a sibling hook, useLayoutEffect; it is rarely needed.

The dependency array

The second argument controls when the effect runs:

Dependency arrayThe effect runs
Not given: useEffect(fn)After every render
Empty: useEffect(fn, [])Once, after the first render (the “mount”)
[a, b]After the first render and after any render where a or b changed

Effect Dependencies is entirely about this array.

App.jsx
JSX
function App() {
  const [renders, setRenders] = React.useState(0);
  const [ran, setRan] = React.useState(0);

  React.useEffect(() => {
    setRan((r) => r + 1);
  }, []); // empty array: only after the first render

  return (
    <div>
      <p>Render triggers: {renders}</p>
      <p>Effect ran {ran} time(s)</p>
      <button onClick={() => setRenders(renders + 1)}>Re-render</button>
    </div>
  );
}

What belongs in an effect

An effect is for synchronising your component with something outside React:

  • the browser: document.title, event listeners on window, timers, focus, scroll
  • a server: requests (though this has better options in frameworks and libraries)
  • third-party widgets: maps, charts, video players
  • a subscription: WebSocket, an event emitter

What does NOT belong in an effect

Many effects people write are not needed. Do not use an effect to:

  • calculate a value from props or state: do it during render (Derived State)
  • respond to a user event: do it in the event handler
  • reset state when a prop changes: use a key
  • chain state updates (an effect sets state, which triggers another effect…)

The lesson Do You Need an Effect? goes through these in detail. A good habit: before you write useEffect, ask “am I synchronising with an outside system?” If not, you probably do not need one.

Effects can run twice in development

In Strict Mode (which the Vite template uses), React mounts, unmounts and mounts your component again in development, to check that your effect cleans up properly. This only happens in development. You will see why in Cleanup Functions and Strict Mode.

Key points

  • useEffect runs code after rendering, to synchronise with something outside React.
  • The dependency array decides when it runs: every render, once, or when listed values change.
  • Do not use effects for calculations or event responses.