Hooks and effects

Write an Effect and its dependencies

Declare synchronization after rendering and list every reactive value the Effect reads.

An Effect runs after React commits the updated interface to the DOM.

import { useEffect } from 'react'

function TaskPage({ tasks }) {
  useEffect(() => {
    document.title = `Tasks: ${tasks.length}`
  }, [tasks.length])

  return <TaskList tasks={tasks} />
}

This Effect keeps the browser document title synchronized with the rendered task count. Add a task and watch the tab title change.

The dependency list describes the reactive values the Effect reads. It is not a performance preference. When tasks.length changes, React runs the synchronization again.

React compares dependencies with their values from the previous render. An object or function created during every render is a new reference and can make an Effect rerun. Move unnecessary object creation inside the Effect or simplify the dependency rather than hiding it from the linter.

Do not suppress a dependency warning to force “run once” behavior. The warning often means the Effect reads a value that can become stale.

An empty array means the Effect does not read changing props or state. It does not mean “ignore values I used.”

Effects are for synchronizing with systems outside React: the document, browser APIs, network subscriptions, or third-party widgets. If the work belongs to a user action, keep it in an event handler instead.

When dependencies change, React runs cleanup from the previous Effect, then runs the new Effect body. That sequence matters for subscriptions and timers. Always return a cleanup function when the Effect sets something up.

The React ESLint plugin compares your dependency array to the values read inside the Effect. Trust the warning unless you can explain why a value is intentionally excluded.

Change a task title without changing the list length, then add a task. Predict which action updates the document title and confirm it in the browser tab.

Lesson completed