Normally in React it is safe to dispose of the tracking tree when unsubscribing the useSyncExternalStore. I can not find explicit documentation on this, but I expect it unsubscribes when the component unmounts or at least all other hooks will also be "reset" (Like throwing related to suspense).
During StrictMode though React will double render to detect "bad effects", including the subscription of a the useSyncExternalStore. This causes an early disposal of the tracking tree. To solve this we do not dispose of the tree related to the subscription in development, but rather add/remove the callback. The tree is lazily disposed when it triggers a track tree which has no related callback to run anymore. This can cause memory leaks in edge cases, but nothing to worry about in development.
Normally in React it is safe to dispose of the tracking tree when unsubscribing the
useSyncExternalStore
. I can not find explicit documentation on this, but I expect it unsubscribes when the component unmounts or at least all other hooks will also be "reset" (Like throwing related to suspense).During
StrictMode
though React will double render to detect "bad effects", including the subscription of a theuseSyncExternalStore
. This causes an early disposal of the tracking tree. To solve this we do not dispose of the tree related to the subscription in development, but rather add/remove the callback. The tree is lazily disposed when it triggers a track tree which has no related callback to run anymore. This can cause memory leaks in edge cases, but nothing to worry about in development.Here is a Sandbox running the refactored code: https://codesandbox.io/p/sandbox/little-hooks-3p998f?file=%2Fsrc%2FApp.tsx%3A46%2C16