Cleanup, and why it runs twice in development
Strict Mode mounting everything twice is not a bug to work around. It is a test you are currently failing.
Cleanup does not only run at unmount. It runs before every re-run of the effect, so a dependency change means teardown then setup. An effect that adds a listener without removing it does not leak once, it leaks on every change of any dependency, and the tenth copy of the handler is why the counter jumped by ten.
Strict Mode mounts, unmounts and remounts every component in development precisely to surface this. If your effect breaks under that, it has a real defect: a subscription that is not removed, a fetch whose response is not ignored, an animation that is started twice. The double invocation is a free test, and the ref guard people reach for is a way of turning the test off.
Fetching in an effect is the canonical case. Two mounts means two requests, and the responses can arrive in either order, so the fix is a cleanup that either aborts the request or sets an ignored flag the response handler checks. That is the same race you fixed in Phase 03, and it is one of the reasons the framework would rather you fetched somewhere else entirely.
You should now be able to
- Write an effect that is safe to run twice
- Explain why cleanup runs on every dependency change, not just unmount
Loading…