Interview frequency: …
Short answer
Cleanup runs before each new execution of the Effect and when the component is removed from the DOM (Unmount); it cancels subscriptions and connections and clears Timers to prevent memory leaks.
Explanation
useEffect runs after Commit and after the screen is updated. If the Effect returns a function, React stores it and runs it before the next Effect (when dependencies change) and before destroying the component, avoiding conflicts or state updates on a removed component.
Code example
useEffect(() => {
const controller = new AbortController();
fetch('/api/user-status', { signal: controller.signal })
.then(res => res.json())
.then(data => setStatus(data));
return () => {
// Cleanup function cancels the request when the component unmounts or reruns
controller.abort();
};
}, [userId]);Common mistakes
- Forgetting to remove event listeners such as window.addEventListener or WebSockets in the Effect's cleanup function.
Follow-up questions
- How do useEffect and useLayoutEffect differ in when they run relative to screen painting?
- What are Stale Closures with useEffect and useCallback, and how do you address them?