Skip to the solution
EasyFrontend6 min read

What is the purpose of React.StrictMode?

319 views

The problem

Question presented to candidate: "Your app is wrapped in <StrictMode> and someone notices every effect appears to run twice in development. Is that a bug? What is StrictMode actually for?"

What a strong answer should cover:

  • It is a development-only tool. It renders no UI and is completely inert in production builds.
  • It intentionally double-invokes component render functions, and mounts-unmounts-remounts to run each effect twice.
  • The purpose: surface bugs that would otherwise appear only later β€” impure renders and missing effect cleanup.
  • Double-invoking render exposes side effects hiding in the render phase, since a pure function run twice is harmless.
  • The mount-unmount-remount cycle exposes effects that do not clean up after themselves.
  • It also warns about deprecated and legacy APIs.
  • Crucially: it does not change production behaviour, so "fixing" it by removing StrictMode hides a real bug rather than solving it.
  • Forward-looking: the remount simulation prepares components for features that preserve and restore state.

Clarifying questions expected:

  • "Is the double-run happening in production too?" (It should not be β€” that would point elsewhere.)
  • "Which React version?" β€” the effect double-invoke behaviour arrived in React 18.

Code / implementation expected: Optional. A subscription effect with correct cleanup is the natural demonstration.

  • development
  • debugging
  • best practices
  • strictmode

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read Β· 8 sections

Try it in the playground

Open any example in the playground to run and change it.

ReactAn effect that survives StrictMode, next to one that leaks
import { StrictMode, useState, useEffect, useRef } from "react";

// Module-level counters so we can see the leak across a simulated remount.
const live = { good: 0, bad: 0 };

// βœ… Correct: cleanup undoes the setup, so mount β†’ cleanup β†’ mount ends with
// exactly one live interval no matter how many times React runs it.
function GoodTimer() {
  const [n, setN] = useState(0);
  const [live_, setLive] = useState(0);

  useEffect(() => {
    live.good += 1;
    setLive(live.good);
    const id = setInterval(() => setN((v) => v + 1), 1000);
    return () => {
      clearInterval(id);
      live.good -= 1;
    };
  }, []);

  return <p>βœ… With cleanup β€” ticks: {n} Β· live intervals: {live.good}</p>;
}

// ❌ Broken: no cleanup. StrictMode's remount leaves TWO intervals running,
// so this counter climbs twice as fast. That is the bug being surfaced.
function LeakyTimer() {
  const [n, setN] = useState(0);

  useEffect(() => {
    live.bad += 1;
    setInterval(() => setN((v) => v + 1), 1000);
    // no return β€” nothing is ever torn down
  }, []);

  return <p>❌ No cleanup β€” ticks: {n} Β· intervals created: {live.bad}</p>;
}

export default function App() {
  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.6 }}>
      <StrictMode>
        <GoodTimer />
        <LeakyTimer />
      </StrictMode>
      <p style={{ color: "#666", fontSize: 13 }}>
        Both effects run twice here because StrictMode simulates a remount.
        The first settles back to one live interval; the second never cleans
        up, so it accumulates two and counts at double speed. The fix is the
        cleanup function β€” not removing StrictMode.
      </p>
    </div>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 20 of 119 in React.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All React.js questions
Up nextEasy

How do you manage component-level state without `useState` or `useReducer`?

Continue