Skip to solution
easyFrontend

What is the purpose of `React.StrictMode`?

318 views
01

Understand 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.

developmentdebuggingbest practicesstrictmode
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for React interviews — assumes familiarity with useEffect. Difficulty: Easy to Medium

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. The render and effect counts below were produced

Solution ready — 2 min read

Classified // press E to declassify

04

Explore the playground snippets

An effect that survives StrictMode, next to one that leaks
Run Playground
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>
  );
}
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 20 of 119 decoded in the React.js track. One more won't hurt.

Back to track