DeployU
Interviews / Frontend Engineering / This component makes duplicate API calls in development. How does Strict Mode help identify the bug?

Questions

This component makes duplicate API calls in development. How does Strict Mode help identify the bug?

debugging Debugging & Tools Interactive Quiz Code Examples

The Scenario

A developer is working on a component that sets up a setInterval to log a message every second. They’ve noticed that in development mode, the message appears twice as often as expected (every 0.5 seconds instead of every 1 second). This behavior is confusing, and they suspect something is wrong with their useEffect setup.

They’ve also noticed that this only happens in development mode, and not in production.

The Challenge

You’ve been given the Timer component, which is wrapped in React.StrictMode.

  1. Explain why the setInterval is running twice as often as expected in development mode.
  2. How does React.StrictMode help identify this type of bug?
  3. Fix the useEffect to ensure the setInterval runs at the correct frequency (once per second), even when React.StrictMode is active.
Your Code
import React, { useEffect } from 'react';

function Timer() {
  useEffect(() => {
    // THE BUG: This effect sets up a setInterval but lacks a cleanup function.
    // In Strict Mode, effects are double-invoked, leading to duplicate intervals.
    const intervalId = setInterval(() => {
      console.log('Timer tick!');
    }, 1000);

    // Missing cleanup function!
  }, []);

  return <div>Check the console for timer ticks.</div>;
}

export default function App() {
  return (
    <React.StrictMode>
      <Timer />
    </React.StrictMode>
  );
}
Click "Run Code" to see output...
Click "Run Code" to see test results...

The Explanation: Strict Mode’s Double Invocation and Effect Cleanup

Wrong Approach

[object Object]

Right Approach

[object Object]

Why Strict Mode Does This

The problem you’re observing is a direct consequence of React Strict Mode. In development mode, React.StrictMode intentionally double-invokes certain lifecycle methods and effects (including useEffect’s setup and cleanup functions).

Why does Strict Mode do this? Strict Mode’s goal is to help developers identify potential problems and ensure their components are resilient to future changes in React. By double-invoking effects, it helps uncover:

  1. Missing cleanup functions: If an effect sets up a subscription, timer, or event listener but doesn’t clean it up, double-invocation will cause two instances to run simultaneously, as seen here.
  2. Non-idempotent side effects: If an effect performs an action that has observable side effects (like fetching data or modifying global state) and doesn’t produce the same result when run twice, Strict Mode will highlight this.

In our Timer component, the useEffect sets up a setInterval but lacks a cleanup function. When Strict Mode runs the effect twice:

  1. First invocation: setInterval is called, intervalId_1 is created.
  2. Second invocation (simulated unmount/remount): setInterval is called again, intervalId_2 is created. Since there’s no cleanup, both intervalId_1 and intervalId_2 continue to run, leading to two “Timer tick!” logs per second.

The Fix: Implementing a Cleanup Function

The solution is to provide a cleanup function for the useEffect hook. This function is returned by the effect and is executed:

  • Before the effect re-runs (if dependencies change).
  • When the component unmounts.
  • Crucially, in Strict Mode, it runs after the first invocation and before the second invocation, effectively “resetting” the effect.
import React, { useEffect } from 'react';

function Timer() {
  useEffect(() => {
    const intervalId = setInterval(() => {
      console.log('Timer tick!');
    }, 1000);

    // FIX: Return a cleanup function to clear the interval.
    // Strict Mode will call this cleanup after the first setup,
    // then set up the effect again.
    return () => {
      clearInterval(intervalId);
      console.log('Timer cleanup!'); // You'll see this log in Strict Mode
    };
  }, []); // Empty dependency array to run once on mount/unmount cycle

  return <div>Check the console for timer ticks.</div>;
}

export default function App() {
  return (
    <React.StrictMode>
      <Timer />
    </React.StrictMode>
  );
}

With the cleanup function, when Strict Mode double-invokes the effect:

  1. Effect setup runs, intervalId_1 is created.
  2. Cleanup runs, intervalId_1 is cleared.
  3. Effect setup runs again, intervalId_2 is created. Now, only intervalId_2 is active, and the timer ticks at the correct frequency.

Practice Question

What is the primary purpose of `React.StrictMode` in development mode?