Commit 95ad182
fix(react): defer unmaterializedNodes cleanup during active Suspense (#360)
When a component inside a <Suspense> boundary creates a SelectorInstance
during render and a sibling throws a promise, React discards the entire
subtree — useEffect never runs, so the selector never gets an observer.
A component above the boundary can then commit its useEffect, triggering
unmaterializedNodes cleanup that destroys the orphaned selector. If that
selector was the only observer of a ttl:0 atom, the atom is destroyed
too, causing an infinite Suspense loop.
Track active Suspense promises via a WeakSet and counter. Defer
unmaterializedNodes cleanup while any Suspense promise is pending. When
the promise settles, React re-renders the children, useEffect creates
proper observers, and cleanup runs naturally — by which point selectors
have observers and destroy() respects their ref count.
Uses .then(fn, fn) instead of .finally() to avoid propagating rejections
into unhandled promise rejections (ErrorBoundary handles those).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>1 parent 7164e92 commit 95ad182
File tree
2 files changed
+719
-1
lines changed- packages/react
- src/hooks
- test/integrations
2 files changed
+719
-1
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
29 | 36 | | |
30 | 37 | | |
31 | 38 | | |
| |||
180 | 187 | | |
181 | 188 | | |
182 | 189 | | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
183 | 196 | | |
184 | 197 | | |
185 | 198 | | |
| |||
205 | 218 | | |
206 | 219 | | |
207 | 220 | | |
208 | | - | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
209 | 239 | | |
210 | 240 | | |
211 | 241 | | |
| |||
0 commit comments