Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Suggestion] Document the usage of flushSync with createRoot.render for synchronous rendering #7317

Open
jukben opened this issue Dec 2, 2024 · 3 comments

Comments

@jukben
Copy link

jukben commented Dec 2, 2024

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!

@rickhanlonii
Copy link
Member

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.

@jukben
Copy link
Author

jukben commented Dec 4, 2024

It's linked in the post – https://codesandbox.io/p/sandbox/react-and-synchronous-react-render-jkpcz7?file=%2Fsrc%2Findex.js (or did you expect full fledged one with React Router? I thought it's not necessary as I'm able to demonstrate what's happening here..)

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.

@jukben
Copy link
Author

jukben commented Dec 11, 2024

@rickhanlonii I'm excited to learn more. 🙏

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants