Omnistac / zedux

:zap: A Molecular State Engine for React
https://Omnistac.github.io/zedux/
MIT License
358 stars 7 forks source link

fix: useAtomSelector - subscribe to the new selector before destroying the old #101

Closed bowheart closed 4 months ago

bowheart commented 4 months ago

Description

When useAtomSelector's useEffect's cleanup function runs, it can destroy any ttl: 0 atoms before the useEffect body generates the new cached selector that should be keeping those atoms around.

While this extra destruction/recreation shouldn't usually cause problems, it can lead to a bug when such an atom is created outside React, given updated state, and then subscribed to by only the selector that is then destroyed. The best practice is to not give ttl (especially not ttl: 0) to atoms you intend to pre-cache or manage outside React. But still, Zedux can at least not make things worse in this case.

Use queueMicrotask very strategically to work around React's timing here. Defer cleanup of the old selector cache until the new effect run has subscribed to the new selector cache.

Also fix the annoying double renders and double selector invocations we added with the recent selector changes. It was very complex to work around those, so I've been putting it off. But I finally got it using:

These work around React StrictMode's behavior of completely destroying the first-rendered component before any effects can run.

Also clean up Selectors#_storage on ecosystem wipe and update tests.