Detailed explanation
StrictMode is a React component that enables extra development-only checks for the component tree inside it. You can wrap your application with <StrictMode><App /></StrictMode>; it adds no DOM element and does not change the production UI. Its purpose is to expose bugs that might otherwise remain hidden, especially impure rendering, incomplete Effect cleanup, and deprecated API usage. When an Effect appears to run twice during initial mounting, StrictMode is often the reason, not an incorrect dependency array.
With StrictMode enabled at the root, React performs an extra setup-and-cleanup cycle for Effects in development. For useEffect(() => { /* setup */ return cleanup; }, []), the initial sequence is setup, cleanup, then setup again. This is often described as mounting, unmounting, and remounting, but that description is shorthand: React is testing the Effect lifecycle, not simply throwing away all component state and creating an unrelated component. React also calls component render functions an extra time to detect impure rendering. These render checks and Effect checks are related safeguards, but they are different mechanisms. In current React, a StrictMode boundary below a non-strict root does not trigger this extra initial Effect cycle.
An Effect synchronises a component with something outside React, such as an event listener, timer, subscription, or network connection. Its cleanup should undo the setup: remove the listener, clear the timer, unsubscribe, or disconnect. For example, if setup starts an interval, return a function that calls clearInterval with that interval's ID. For data fetching, cleanup can abort the request where supported or mark its result as obsolete so it cannot update state. Aborting does not guarantee that a request already received by the server is undone.
Interviewers look for an explanation of the lifecycle and a safe fix, rather than a trick to suppress the second execution. Do not remove StrictMode or add a ref guard just to hide missing cleanup. Instead, make repeated setup and cleanup safe, and keep user-triggered actions such as payments in event handlers. Production skips these StrictMode checks, but Effects still rerun when dependencies change or components genuinely remount.
Key points to remember
- StrictMode enables development-only checks and adds no DOM wrapper.
- Root-level StrictMode tests initial Effects with setup → cleanup → setup.
- Extra render calls check purity; extra Effect cycles check cleanup.
- Cleanup must release resources and prevent obsolete asynchronous results from affecting state.
- Production skips StrictMode checks, but normal dependency changes and remounts still rerun Effects.
Common mistakes candidates make
- Removing StrictMode to hide duplicate listeners, timers, or requests instead of fixing their lifecycle.
- Using a ref guard to force one execution, potentially leaving resources disconnected after the cleanup check.
- Assuming an empty dependency array guarantees exactly one execution throughout the application's lifetime.
Likely follow-up questions
Does an empty dependency array prevent the extra execution?
No. An empty dependency array prevents reruns caused by changing dependencies, but it does not bypass StrictMode's development check or genuine remounts.
How should I handle duplicate fetch requests in development?
Use cleanup to abort the request where supported or ignore obsolete responses, and consider a data-fetching library with caching and request deduplication. Cleanup protects client-side behaviour, but cannot reliably undo server-side work that has already started.
Does cleanup run only when a component unmounts?
No. It also runs before an Effect is set up again after its dependencies change, as well as during StrictMode's extra development cycle. The cleanup uses the values captured by the corresponding setup.
Interview tip: Explain the setup → cleanup → setup sequence, give one concrete cleanup example, and distinguish development checks from normal production reruns.
