Interview answer drill

Use this React interview question to rehearse a quick answer, common mistake, follow-up, and production pitfall.

Why does StrictMode double-invoke effects in dev? What bugs does it expose?Frontend interview answer

HighIntermediateReact
Interview focus

This React interview question tests whether you can explain React StrictMode double effects: cleanup bugs, duplicate side effects, and dev-only diagnostics, connect it to production trade-offs, and handle common follow-up questions.

  • React StrictMode double effects: cleanup bugs, duplicate side effects, and dev-only diagnostics explanation without falling back to memorized docs wording
  • Effects and Best Practices reasoning, edge cases, and production failure modes
  • How you would answer the most likely React interview follow-up
Practice more React interview questions
Interview quick answer

Explain StrictMode double effect invocation as a dev-only diagnostic for missing cleanup, duplicate side effects, and code that is not safe under remounts or concurrent-style replay.

Full interview answer

Debug diagnostic

StrictMode double-invokes effects in development to flush out bugs that stay hidden when code assumes “this only runs once.” The practical value is finding missing cleanup, duplicate subscriptions, repeated network calls, and non-idempotent side effects before those same assumptions break under remounts, navigation churn, or concurrent-style replay.

Important: this only happens in development

StrictMode checks run only in dev. Production builds do not double-invoke effects. This is a diagnostic tool, not a performance feature.

The mental model

React is preparing for a future where it can pause, discard, and restart renders (concurrent rendering). To make sure your code is safe for that world, StrictMode asks a brutal question:

"If I mount this component, tear it down, and mount it again immediately… does anything break?"

JSX
function Example() {
  useEffect(() => {
    console.log('effect run');
    return () => {
      console.log('cleanup');
    };
  }, []);

  return <div>Hello</div>;
}

// In StrictMode (dev), you'll see:
// effect run
// cleanup
// effect run
                  

What exactly gets double-invoked?

In React 18 StrictMode (dev):
• Component render functions
• useEffect / useLayoutEffect setup + cleanup
• Certain initializers

React mounts, cleans up, and mounts again immediately.

What React is testing

Bad pattern

Bug it exposes

Missing cleanup

Subscribing but never unsubscribing

Memory leaks, duplicate listeners

Non-idempotent side effects

Sending analytics / POST request on mount

Duplicate network calls or double charges

Mutating external state

Pushing into global arrays, singletons

Duplicated or corrupted global state

Assuming effects run only once

“This runs once on mount” logic

Breaks under remounts / transitions

The kinds of bugs StrictMode is hunting

Classic bug example: missing cleanup

JSX
useEffect(() => {
  window.addEventListener('resize', onResize);
  // ❌ No cleanup
}, []);

// In StrictMode dev, this registers the listener twice 😬
                  

Correct version:

JSX
useEffect(() => {
  window.addEventListener('resize', onResize);
  return () => {
    window.removeEventListener('resize', onResize);
  };
}, []);

// ✅ Safe under mount → unmount → mount
                  

Another classic: non-idempotent side effects

JSX
useEffect(() => {
  analytics.track('page_view'); // ❌ will fire twice in dev StrictMode
}, []);
                  

Better patterns:

• Move it to a router-level boundary
• Or make it idempotent
• Or dedupe on the analytics side

Worked fetch example: duplicate request vs cleanup-safe request

The common complaint is “StrictMode fetched twice.” The real question is whether the effect is safe when React remounts the component or the user changes routes quickly.

JSX
// ❌ Duplicate fetch and late stale response can win after remount/navigation
useEffect(() => {
  fetch(`/api/profile/${userId}`)
    .then((r) => r.json())
    .then(setUser);
}, [userId]);

// ✅ Abort the old request when StrictMode remounts or the route changes
useEffect(() => {
  const controller = new AbortController();

  fetch(`/api/profile/${userId}`, { signal: controller.signal })
    .then((r) => r.json())
    .then((data) => {
      if (!controller.signal.aborted) setUser(data);
    })
    .catch((error) => {
      if (controller.signal.aborted) return;
      setError(error);
    });

  return () => controller.abort();
}, [userId]);
                  

Why the route-switch scenario matters

Dev-only replay maps to real user behavior. A user can open a profile, navigate away immediately, and come back. If your effect leaks subscriptions or lets an old request commit after unmount, that is a production bug even though StrictMode is what exposed it first.

Extra render checks vs extra effect re-runs

StrictMode stresses more than one surface. Extra render calls catch impure render logic. Extra effect setup/cleanup cycles catch missing cleanup and non-idempotent side effects. Keep those two diagnostics separate when debugging double logs.

Why React does this (the real reason)

Concurrent React may mount, pause, throw away, and restart trees. If your effects are not resilient to being started and stopped multiple times, you’ll get production-only bugs. StrictMode forces you to see them early.

What this is NOT

• Not a bug
• Not React being slow
• Not something to “work around”

It’s a correctness check.

Rule of thumb

Write effects as if React can run them, clean them up, and run them again at any time. If that is safe, your code is future-proof.

Interview framing

Say it like this:
"StrictMode double-invokes effects in dev to simulate mount–unmount–remount and catch unsafe side effects. It exposes missing cleanups, non-idempotent logic, and code that assumes effects run only once. This is to prepare apps for concurrent rendering and only runs in development."

Summary

StrictMode intentionally double-invokes effects in development to detect unsafe side effects and missing cleanup. It helps catch memory leaks, duplicated subscriptions, non-idempotent logic, and code that assumes a single mount. This behavior is dev-only and exists to make apps safe for concurrent rendering.

Similar questions
Guides
Preparing for interviews?

Use this as one explanation rep, then continue with the React interview questions cluster or a guided prep path.