Engrain by ByteRush

RCT.04.01 Mid-level· 11 minCore — asked often

Effects synchronize with external systems

Think of useEffect as keeping something outside React in sync with your props and state, not as lifecycle methods. Learn when effects run, why cleanup runs before every re-run, and why StrictMode mounts twice.

Comes up in: React, Recruiter screen

Learn#

Sana’s chat page stays connected to the “general” room after the user switches to “travel”. Her effect has an empty dependency array, because she thought of it as “on mount”.

An effect keeps an external system, such as a connection, a subscription or a browser API, in step with your props and state. That is synchronization: whenever the values it uses change, stop syncing the old values and start syncing the new ones:

import { GlobalRegistrator } from "@happy-dom/global-registrator";
GlobalRegistrator.register(); // a DOM for Node; in a browser you already have one
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
const { createElement: h, useEffect, act } = await import("react");
const { createRoot } = await import("react-dom/client");

function ChatRoom({ room, theme }) {
  useEffect(() => {
    console.log(`connect to ${room}`);
    return () => console.log(`disconnect from ${room}`);
  }, [room]); // re-sync only when room changes
  return h("h2", { className: theme }, room);
}
const root = createRoot(document.createElement("div"));
await act(() => root.render(h(ChatRoom, { room: "general", theme: "light" })));
await act(() => root.render(h(ChatRoom, { room: "general", theme: "dark" }))); // theme only
await act(() => root.render(h(ChatRoom, { room: "travel", theme: "dark" })));
await act(() => root.unmount());
This example uses Node.js, so it runs in our checks rather than in your browser.

Output (verified)

connect to general
disconnect from general
connect to travel
disconnect from travel

The cleanup function runs before the effect runs again, and once more when the component unmounts.

An effect re-syncs when room changesStep 1 of 4

Console

  • connect to general

State

    empty

    Mount with room "general". After paint, the effect connects to general.

    Read the steps as text
    1. Mount with room "general". After paint, the effect connects to general.
    2. theme changes to dark. room did not change, so the effect does not run again.
    3. room changes to travel. First the old cleanup runs with the old room, then the effect runs with the new one.
    4. Unmount: the last cleanup runs. Every connect has exactly one matching disconnect.

    Predict#

    Predict first

    Is useEffect(fn, []) the same as componentDidMount?

    Interview angle#

    Say it like this — about 30 seconds

    “An effect synchronizes something outside React with the current props and state. It runs after the browser paints. The dependency array is not a lifecycle choice; it lists every reactive value the effect uses, so React re-runs it when one of them changes. Before each re-run, and on unmount, React runs the previous cleanup. In development, StrictMode mounts, unmounts and mounts again to prove the cleanup works. Many effects should not exist at all: derive data during render, and handle events in handlers.”

    Stays on your device. Nothing is uploaded.
    Follow-up When does the effect cleanup function run?
    Before the effect runs again with new dependencies, and when the component unmounts.
    Follow-up Give examples of effects you should remove.
    Computing derived data, resetting state when a prop changes, sending a request in response to a click, and chains of effects that set state for each other (RCT.04.02).
    Follow-up Why is useEffect with an empty array not the same as componentDidMount?
    It runs after paint, captures the first render’s values, must be paired with cleanup, and runs twice in development StrictMode.

    Practice#

    Guided

    Simulate React’s effect timing for a list of renders, with and without StrictMode.

    Done when

    • The effect re-runs only when a dependency changed, after the previous cleanup.
    • Unmount runs the last cleanup.
    • Strict mode adds one cleanup and re-run right after the first run.
    Your solution
    Ctrl/⌘ + Enter

    Remember#

    Try to answer each card before you open it. Then add them to your reviews.

    When does useEffect run?

    After the render is committed and the browser has painted.

    When does an effect's cleanup run?

    Before the effect re-runs, and on unmount.

    What should the dependency array contain?

    Every reactive value the effect uses.

    What does StrictMode do to effects in development?

    Runs setup, cleanup, then setup again on mount.

    Go deeper

    Four layers. Stop at the one your interview needs; each ends with a quick check.

    The core ideaEvery round

    Effects run after the commit and, usually, after the browser paints, so they never block the screen.
    Reactive values are props, state and anything calculated from them; all of them used by the effect belong in its dependency list.

    Check yourself: What are reactive values?

    Props, state and anything computed from them during render.

    How it works underneathSenior rounds

    Each render has its own effect and cleanup, closing over that render’s values. So the cleanup for “general” disconnects from general, even after room is “travel” Source: React: Lifecycle of reactive effects.

    Check yourself: Which values does a cleanup see?

    The values from the render whose effect it cleans up.

    Edge cases and trapsWhere people slip
    In development, StrictMode runs setup, cleanup, setup for each effect on mount. If that breaks your app, the cleanup is missing or incomplete; users would hit the same bug when navigating away and back.
    Check yourself: Does StrictMode's double mount happen in production?

    No, only in development.

    In productionStaff-level answers
    The timeline is: render, commit, paint, effect; on change: cleanup with old values, then effect with new ones; on unmount: cleanup. Every subscription, timer and listener needs its cleanup Source: React: useEffect.
    Check yourself: Name an effect timeline step that is easy to forget.

    Cleanup on unmount, for timers, listeners and connections.

    Finished the five steps? Mark it, and its cards join your reviews.

    Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

    Interview questions this answers

    • When does the effect cleanup function run?
    • Give examples of effects you should remove.
    • Why is useEffect with an empty array not the same as componentDidMount?