Replies: 1 comment 1 reply
-
The change is that layout effects now get unmounted when a Suspense boundary gets resuspended. What happens here is that when that happens the inner root gets unmounted. So there’s nothing suspended anymore so it unsuspends and that then tries to render it again which suspends. And so on. I don’t know of any really good workarounds atm that also works in strict mode. Maybe moving the unmount to a useEffect and also render in the same one. However regardless this strategy has a new flaw in 18. It doesn’t work with startTransition. Because if the update outside the Canvas has a startTransition on it, it’s supposed to delay mounting the tree if it’s suspended but instead it’ll mount and then get a second update that resuspends and that second update is not a startTransition. So that would force the suspense fallbacks to show. Negating the purpose of a startTransition. This kind of coordination can’t be done outside React. The ideal solution would be cross-renderer Portals but we don’t know how to version them yet. So I would actually recommend that the Canvas always accepts a fallback argument that it’s always required to have its own Suspense boundary fallback at the root. That ensures that if the parent uses startTransition it doesn’t force a too high fallback to be shown instead that wasn’t intended. |
Beta Was this translation helpful? Give feedback.
-
The use case
React does not allow suspense and error-boundaries to be shared among mixed renderers. It's been a long standing issue. We are forced to circumvent it by forwarding it by ourselves, which has worked OK.
React 17 and 18
✅ React 17: https://codesandbox.io/s/focused-cherry-dz0hh?file=/src/App.js Works fine. In this demo i mock the custom renderer by using another react-dom root.
❌ React 18: https://codesandbox.io/s/nice-bhabha-7zsje?file=/src/index.js It creates an infinite loop, it starts to unmount the Canvas component repeatedly. I've stopped it at 4 repeats so that it doesn't sink codesandbox ...
What does it do
Basically it just setStates suspense and errors from the inner renderer to the outer, and then throws in the outer. That allows the user to suspend a mixed renderer, or catch its errors. This is how react-three-fiber operates for a longer while.
Why does React 18 behave differently?
Does anyone know what has changed and why the behaviour is different, is this a bug in React 18?
Beta Was this translation helpful? Give feedback.
All reactions