Skip to main content

Effects and Refs

useEffect Explained

Written by Published

An effect is for reaching outside React - a network request, a subscription, a timer, the document title. If the code only computes a value, it does not belong in one.

What an effect is for

React renders your component and updates the DOM. Anything else the component needs to do - talk to a server, start a timer, listen to the window - happens after that, and useEffect is where it goes.

Running after render

jsx

function Title() {
  const [count, setCount] = React.useState(0)

  React.useEffect(() => {
    // Runs after React has updated the DOM.
    document.title = `Count: ${count}`
  })

  return (
    <div>
      <p>Count: {count}</p>
      <p style={{ color: "#64748b" }}>The browser tab title follows this number.</p>
      <button onClick={() => setCount(count + 1)}>Add</button>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<Title />)

Most code is not an effect

This is the most common misuse. If a value can be calculated from props or state, calculate it during render. Putting it in an effect adds a second render, a chance to be out of date, and nothing else.

Derived, not effected

jsx

function Cart() {
  const [items, setItems] = React.useState([2, 5])

  // Wrong: an effect and extra state to hold something derivable.
  // const [total, setTotal] = useState(0)
  // useEffect(() => { setTotal(items.reduce((a, b) => a + b, 0)) }, [items])

  // Right: just compute it.
  const total = items.reduce((sum, n) => sum + n, 0)

  return (
    <div>
      <p>Items: {items.join(", ")} — total {total}</p>
      <button onClick={() => setItems([...items, 3])}>Add 3</button>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<Cart />)

The commented-out version works, but renders twice for every change and can display a stale total for one frame. Deriving is simpler and always correct.

What genuinely needs one

  • Fetching data from a server.
  • Subscribing to something - a socket, an event listener, a store.
  • Timers: setInterval and setTimeout.
  • Manually touching the DOM outside React's tree, like the document title.
  • Logging or analytics tied to something appearing.

If your effect does not appear on that list, ask what it is really for. An effect that only calls a setter based on props is usually a derived value in disguise.

It runs after paint

The user sees the rendered output first, then the effect runs. That is deliberate - it keeps rendering fast - but it means an effect that sets state causes a visible second render. Another reason not to use one for values you could compute directly.