React Strict Mode forces useEffects to double render. The problem is that this causes the cleanup code to run on page enter AND exit. Instead of just on exit like the cleanup should do.
useEffect(() => {
return () => {
console.log('do you only call once?')
// TODO: Fix why this is resetting to init state when I ENTER instead of just leave
// dispatch(resetToInitialState())
}
}, [])
The above code will trigger once when entering the page, another time when exiting. The issue is that I’d set states before navigating in the page, and the React Strict mode would mean the cleanup resets everything to initial state…
Is there anyway to prevent cleanup from being called on page enter without disabling React Strict mode? Note that I fixed it by disabling React Strict mode, but wanted to keep it on if possible.
3
Answers
I don’t think this can be fixed. This is the native useEffect behavior with Strict Mode, described in the documentation.
https://react.dev/reference/react/StrictMode
In React Strict Mode,
useEffect
cleanup functions are intentionally invoked twice during development for certain scenarios. This helps developers identify potential side effects or cleanup-related issues. Specifically, React calls theuseEffect
cleanup:simulating unmounting and re-mounting to highlight side effects.
If you want to ensure your cleanup logic runs only on an actual unmount (and not during the development-only re-render simulation caused by Strict Mode), you can handle this by detecting whether the component is being unmounted permanently. Here’s how you can achieve it:
Using a
ref
to track mounting stateExplanation
isMounted
ref initializes asfalse
and remains consistent acrossrenders.
won’t execute because
isMounted.current
isfalse
.Strict Mode), the cleanup function is only executed when the
component is truly unmounted.
Key Considerations
Strict Mode Behaviour: This behaviour occurs only in development mode. In production, the
useEffect
cleanup runs once on unmount, as expected.Purpose: React’s strict mode aims to make your app more robust by simulating certain conditions during development. Avoid suppressing this behaviour unless absolutely necessary.
By handling it this way, your app retains proper behaviour while ensuring a clear separation between development simulations and production unmounting.
Be sure that the clean up code of useEffect hook will fire only on unmount event of a component. It will never run on mounting a component.
Please check the logs below create by the following sample code.
Please note that there "Unmounted" has always been logged after "Mounted". There is no "Unmounted" logged repeatedly.
If your observation was right, then there should have been repeated "Unmounted" logs created. It does not happen.
App.js
Console logs
The below three logs created on the initial render
The below four logs created on clicking the button once
The below four logs created on clicking the button a second time