React 18 removed the 'Can't perform a React state update on an unmounted component' warning. Does that mean effects that fetch no longer need cancellation and cleanup?
answer
- the warning was wrong, not the practice
- an unmounted update is a no-op
- ask what is still running
- wasted bandwidth, connections, server work
basics
~20 sNo. The warning was removed because it was wrong — an update on an unmounted component is a harmless no-op, not a leak. What genuinely leaks is anything still running: intervals, subscriptions, observers. And cancelling requests was always about wasted work, not about the console.
solid answer
~50 sNo — the warning went away because it was inaccurate, not because cleanup stopped mattering. Setting state on an unmounted component is a harmless no-op, and the warning pushed people into `isMounted` flags that suppressed a message without stopping any of the work it was blaming. What still genuinely leaks is anything that keeps running after the component is gone: intervals, timeouts, observers, sockets, subscriptions — those only stop if the effect returns a cleanup that stops them. Cancelling an in-flight `fetch` is a separate argument again, and it is about waste rather than leaks: an aborted request frees a connection from the browser's per-host budget, stops the response body downloading, saves the user's bandwidth and battery on a mobile connection, and takes load off a server producing a result nobody will read. None of that ever depended on a console message.
go deeper
Know that updating state on an unmounted component does nothing at all in React 18 and later, and that cleanup is still required for anything the effect left running.
Explain why the warning was inaccurate — a no-op update leaks nothing — and separate genuine leaks such as intervals and subscriptions from in-flight requests, which are a waste problem instead.
Name the concrete costs of not cancelling: connections held against the browser's per-host limit, response bodies downloaded on metered links, and server work whose result is discarded.
Argue the policy: the console no longer flags this class of bug at all, so it has to be caught by review convention, a shared data layer that cancels by default, and traffic that is monitored against user activity rather than session length.
## What the warning said and why it went Before React 18, updating state on a component that had already unmounted logged: *Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application.* React 18 removed it, and the reasoning is the interesting part. The message was self-contradicting. It correctly said the update is a no-op, then asserted a memory leak on that basis — but a no-op update leaks nothing. React drops it and moves on. The genuine leak, when there is one, is whatever is still running and still holding references: the interval, the subscription, the listener. The state setter is merely the most visible symptom of that, and often it is not present at all. Worse, the warning taught a bad fix. To silence it, thousands of codebases added a flag: ```js useEffect(() => { let mounted = true; load().then((data) => { if (mounted) setData(data); }); return () => { mounted = false; }; }, []); ``` That stops the message and stops nothing else. The request still runs to completion, the response body is still downloaded and parsed, the server still did the work. The flag added a line of ceremony, retained one more closure, and left the actual waste untouched — while making the code look as though cleanup had been handled. ## What is true after the removal Calling a state setter on an unmounted component in React 18 and later is silent and inert. No warning, no error, no render. That fact changes exactly one thing: it removes a reason to write cleanup that was never a good reason in the first place. Everything else stands, and it splits into two distinct arguments that candidates routinely merge. **Argument one — real leaks.** Anything an effect starts that keeps running must be stopped, because nothing else will stop it: `setInterval`, `setTimeout`, `requestAnimationFrame`, event listeners, `IntersectionObserver` and `ResizeObserver`, WebSocket connections, subscriptions to any external system. These accumulate across mounts, keep firing on screens the user has left, and retain everything their callbacks close over. This is a correctness and memory problem, and it never had anything to do with the warning. **Argument two — wasted work.** An in-flight `fetch` is not a leak: it settles, its promise is collected, and nothing is retained. Cancelling it is an efficiency and resource argument, and the specifics are what an interviewer wants to hear: - A browser allows only a handful of concurrent connections per host. A component that fires one request per keystroke and cancels none can saturate that budget with obsolete requests, so the request the user is actually waiting on queues behind answers nobody wants. - Aborting stops the response body from being downloaded and parsed — on a slow connection that is the expensive part, and on a metered mobile connection the user pays for it. - Downstream, the server and its database do work whose result is discarded. At one user that is nothing; across a large user base of fast typers it is a measurable share of traffic. - On a page that mounts and unmounts frequently, cancelling keeps the number of in-flight requests bounded by what is on screen rather than by how much the user has clicked. ## How to answer the question in an interview Separate the three claims explicitly. First: an update after unmount is inert, so that is not the reason. Second: whatever the effect started that is still running is a real leak, and only the cleanup function stops it. Third: cancellation of requests is about not paying for answers nobody will read, and about not crowding out requests that matter. The most common weak answer collapses all three into "you have to clean up or you get a memory leak", which is right about the conclusion for the wrong reason, and cannot explain why React deleted the warning. ## What this does not license Removing the warning also removed a diagnostic. It used to be a crude smoke alarm — noisy and often wrong about the cause, but it did fire. Nothing replaced it, so effects that skip cleanup now fail silently: no console output, just growing request volume and timers that outlive their screens. The practical consequence is that this class of bug has to be caught by review and by monitoring rather than by the console, which is a good reason to keep cleanup as a mechanical habit rather than something you add when something complains.
- Why is an isMounted flag a poor substitute for aborting the request?It suppresses the state write and nothing else. The request still completes, the body is still downloaded and parsed, the server still did the work, and the browser connection is still occupied until it finishes. The flag makes the code look cleaned-up while leaving every real cost in place — which is precisely the habit the removed warning encouraged.
- Which of the things an effect starts genuinely leak memory if you skip cleanup?The ones that keep running and hold references: intervals and timeouts, animation frames, event listeners, observers, sockets, and subscriptions. Each keeps its callback and everything that callback closes over reachable, and they accumulate one per mount. An in-flight fetch is not in this group — it settles and is collected — which is why its argument is about wasted work rather than memory.
- With the warning gone, how would you now catch a component that skips cleanup?Not from the console — it is silent now. In review, read each effect's first and last lines and check that anything started is stopped. In production, watch for request volume or timer-driven traffic that grows with session length rather than with user activity, and profile a repeated mount/unmount cycle in DevTools to see whether retained size climbs.
saying these in an interview costs you the question
- Setting state after unmount leaks memory
- The warning is gone, so cleanup is optional now
- An isMounted flag is the recommended fix
- Aborting requests only exists to silence console warnings
- React 18 made unmount cleanup automatic