React useEffect Hook

In the last lesson, the React useState Deep Dive, you got comfortable storing and updating values. This lesson covers useEffect, the hook for work that must happen after React draws the screen, like setting the page title, calling an API, or starting a timer.

🤔 Why do we need useEffect?

A component’s main job is to take state and props and return JSX. But real apps need to do more than that, right?

  • You might want to change the browser tab title when a value changes.
  • You might want to fetch data from a server when the component first shows up.
  • You might want to start a timer, or listen for the window resizing.

None of that work is about returning JSX. It reaches outside the component. So if you try to do it right inside the render, React gets unhappy and your code can break or loop forever. That’s why you need a safe place to run this extra work, and that place is useEffect.

🧩 What is useEffect?

useEffect is a React hook that lets you run a side effect, which means any work that reaches outside of rendering.

  • A side effect is anything that isn’t just calculating and returning JSX. Setting the document title, talking to the network, setting up a timer, subscribing to something.
  • useEffect gives that work a proper home, separate from the render.
  • React runs your effect for you at the right moment, after it has updated the screen.

Think of it like a note you leave for React. You’re saying “once you’re done drawing the screen, go do this extra job for me.”

🔌 Importing useEffect

Before you can use it, you have to bring it in from React, just like useState. This line at the top of your file gives you both hooks at once.

import { useState, useEffect } from "react";

Here’s what that line is doing for you:

  • Both useState and useEffect are named exports from React, so you pull them out by name inside the curly braces.
  • You’ll write this exact import in almost every component that does real work.

🛠️ The syntax

Now the shape of the hook. You call useEffect with two things: a function, and a list.

useEffect(() => {
// your side effect goes here
}, [deps]);

Let’s read the two parts.

  • The first part is a function. This is your effect, the actual work you want to run, like setting the title or fetching data.
  • The second part is an array called the dependency array. It tells React when to run that function again.
  • You almost always pass both parts. The function says what to do, and the array says when.
  • Don’t worry about getting the array perfect yet. For now, just know it controls timing, and the next few lessons go deep on it.

⏰ Effects run after render

This is the key idea to hold onto. Your effect does not run during the render. It runs after React has finished drawing the screen.

  • First React runs your component and returns the JSX.
  • Then React puts that JSX on the screen for the user to see.
  • Only after that does React run your effect function.

So the order is always render first, then effect. This is on purpose. It keeps rendering fast and pure, and it means your effect runs when the screen is already updated and safe to touch.

Why after, not during?

Rendering should only calculate and return JSX, nothing more. Running side effects during render would make components slow and unpredictable. So React waits until the screen is updated, then runs your effect.

🔁 The three forms by dependency array

The dependency array is the second argument, and it changes how often your effect runs. There are three forms to know at a high level.

  • No array at all → the effect runs after every render. Every single time the component re-draws, the effect runs again.
  • Empty array [] → the effect runs once, after the first render only. Great for setup work like fetching data when the component appears.
  • Array with values [count] → the effect runs after the first render, and again any time one of those values changes.

So the array is like a watch list. React looks at it after each render and decides whether to run your effect again.

Leaving the array out is rarely what you want

An effect with no dependency array runs after every render. That sounds harmless, but it often causes far more work than you expect, and sometimes endless loops. Most of the time you want either an empty array or a list of values.

💡 A simple example: update the document title

Let’s put it together with the classic example. This component keeps a count in state, and uses an effect to set the page title whenever that count changes.

import { useState, useEffect } from "react";
function Counter() {
const [count, setCount] = useState(0);
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>
);
}

Let’s walk through what happens here.

  • const [count, setCount] = useState(0) sets up the count state, starting at 0.
  • useEffect(() => { ... }, [count]) says: run this effect, and run it again whenever count changes.
  • Inside the effect, document.title = ... updates the browser tab text. That’s the side effect, since it reaches outside React into the page.
  • On the first render the title becomes “You clicked 0 times”. Then click the button and count changes, so React re-renders and runs the effect again with the new number.

So the tab title now stays in sync with the count, all on its own. That’s the whole pattern: state changes, screen updates, effect runs.

Setting the title is a perfect first effect

Updating document.title is a clean example because it’s simple and you can see it work in the browser tab. The same pattern handles bigger jobs too, like fetching data or starting a timer.

🧩 What You’ve Learned

  • useEffect lets you run side effects, which is work that reaches outside rendering
  • ✅ Side effects include setting the document title, fetching data, starting a timer, or subscribing to something
  • ✅ You import it with import { useState, useEffect } from "react"
  • ✅ The syntax is useEffect(() => { ... }, [deps]): a function for what to do, and an array for when
  • ✅ Effects run after React draws the screen, never during the render
  • ✅ No array runs the effect after every render, [] runs it once after the first render, and [value] runs it when that value changes
  • ✅ A common first effect is updating document.title whenever a count changes

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    What is useEffect mainly used for?

    Why: useEffect is for side effects, meaning work that reaches outside of rendering. Storing a value is useState's job, and returning JSX is the render's job.

  2. 2

    When does a useEffect function run?

    Why: Effects run after render. React first returns the JSX and updates the screen, then it runs your effect function.

  3. 3

    What does an empty dependency array [] do?

    Why: An empty array tells React there are no values to watch, so the effect runs just once after the first render. That makes it good for setup work.

  4. 4

    In useEffect(() => { ... }, [count]), when does the effect run again?

    Why: When you list a value in the array, React runs the effect after the first render and again any time that value changes. So here it runs whenever count changes.

🚀 What’s Next?

You’ve got the big picture now: what an effect is, that it runs after render, and how the dependency array controls timing. Next you’ll zoom in on the empty array form and see exactly how to run an effect just once, when the component first appears.

React useEffect on Mount

Share & Connect