Questions
This component makes duplicate API calls in development. How does Strict Mode help identify the bug?
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.
- Explain why the
setIntervalis running twice as often as expected in development mode. - How does
React.StrictModehelp identify this type of bug? - Fix the
useEffectto ensure thesetIntervalruns at the correct frequency (once per second), even whenReact.StrictModeis active.
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>
);
} The Explanation: Strict Mode’s Double Invocation and Effect Cleanup
[object Object]
[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:
- 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.
- 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:
- First invocation:
setIntervalis called,intervalId_1is created. - Second invocation (simulated unmount/remount):
setIntervalis called again,intervalId_2is created. Since there’s no cleanup, bothintervalId_1andintervalId_2continue 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:
- Effect setup runs,
intervalId_1is created. - Cleanup runs,
intervalId_1is cleared. - Effect setup runs again,
intervalId_2is created. Now, onlyintervalId_2is active, and the timer ticks at the correct frequency.
Practice Question
What is the primary purpose of `React.StrictMode` in development mode?