You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While integrating React Router (using RouterProvider), we ran into an issue. After moving most of our routes to use loader for the fetch-as-you-render pattern, we noticed that some routes with very simple or fast loaders were breaking the app.
The problem comes down to a timing issue (this was tricky to debug since it only happened in the production build and only when the console wasn’t open—though I’m not sure why, and it might be a red herring). React Router subscribes to its internal state in a useLayoutEffect (relevant code), but if the loaders finish before this subscription happens, the root app component doesn’t get the update and can’t proceed with rendering.
While looking for a way to flush updates synchronously (shoutout to this Stack Overflow post), I learned that the flushSync API can handle this (I never though about using this API outside of React, I mean before initial render...).
I think this behavior should be mentioned on react.dev (in the createRoot section?). It’s a key detail for anyone needing synchronous rendering in cases like this (similar to how React worked before Concurrent Mode).
I’m also not sure if React Router’s current approach is the best way to handle this. I’ll open an issue with them as well to suggest adding something about this edge case in their documentation.
Happy to help push this forward—just let me know the next steps!
The text was updated successfully, but these errors were encountered:
Can you provide a sandbox of the bug? You really should not need to do this since the initial render is already sync by default, so this may only be an issue when using a concurrent feature, which calling flushSync would break. I'd need to see an example to understand better.
Let me know. I was wondering if it's bug or not, on the other hand I haven't found any mention that this initial render is expected to happen synchronously (but I propose to be explicit that it's async at least), so I'm not really sure. Thanks for looking into it. 🙏
EDIT: Sorry, the sandbox might have had been private, I think it used to be public by default 😅 Should work now.
since the initial render is already sync by default
This is interesting, because this was exactly my expectation. However the sandbox doesn't support it. I'd most likely expect that the old mode would behave the same as concurrent mode (3. and 1. in the example above).
Summary
Document the usage of the flushSync API with render to achieve synchronous initial rendering, effectively mimicking pre-Concurrent Mode behavior.
Page
https://react.dev/reference/react-dom/client/createRoot
Details
While integrating React Router (using RouterProvider), we ran into an issue. After moving most of our routes to use loader for the fetch-as-you-render pattern, we noticed that some routes with very simple or fast loaders were breaking the app.
The problem comes down to a timing issue (this was tricky to debug since it only happened in the production build and only when the console wasn’t open—though I’m not sure why, and it might be a red herring). React Router subscribes to its internal state in a useLayoutEffect (relevant code), but if the loaders finish before this subscription happens, the root app component doesn’t get the update and can’t proceed with rendering.
While looking for a way to flush updates synchronously (shoutout to this Stack Overflow post), I learned that the flushSync API can handle this (I never though about using this API outside of React, I mean before initial render...).
Here’s a sandbox example showing how it behaves.
I think this behavior should be mentioned on react.dev (in the createRoot section?). It’s a key detail for anyone needing synchronous rendering in cases like this (similar to how React worked before Concurrent Mode).
I’m also not sure if React Router’s current approach is the best way to handle this. I’ll open an issue with them as well to suggest adding something about this edge case in their documentation.
Happy to help push this forward—just let me know the next steps!
The text was updated successfully, but these errors were encountered: