Uh oh!
There was an error while loading. Please reload this page.
Implement workaround for hydration error on React strict mode - #3637
Implement workaround for hydration error on React strict mode#3637ciffelia wants to merge 3 commits into
Conversation
b1c4f4d to
8f116e3Compare
snowystinger
left a comment
There was a problem hiding this comment.
Thanks so much for starting this!
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Robert Snow <snowystinger@gmail.com>
ciffelia
commented
Oct 13, 2022
I'll update |
- remove implementation details - mention `identifierPrefix`
devongovett
commented
Oct 14, 2022
Any idea why the original implementation doesn't work in strict mode? Is the Switching to |
ciffelia
commented
Oct 15, 2022
Maybe possible with a ref. Something like this? functionuseId(){// ...letref=useRef(null);if(ref.current==null){ref.current="react-aria-"+ctx.current++// ...}returnref.current}(Typed on mobile, sorry for any mistakes) |
I see. I think that idea would work well on React 17, but would cause hydration errors in concurrent mode on React 18, where the client and the server may not render components in the same order. |
ciffelia
commented
Oct 27, 2022
I believe @devongovett do you have any ideas? |
devongovett
commented
Oct 29, 2022
I believe that is only a problem when using the brand new streaming server renderer, which is only for Server Components not traditional SSR. Also we still support React 16 and 17, so we should fix the issue there as well. I think the approach I posted above might work for 16, 17, and regular SSR in 18. We would need to switch to React.useId for Server Components support at some point, but I'm concerned that there will be side effects from such a change. React Aria's |
ciffelia
commented
Oct 30, 2022
Thanks for the explanation. That makes sense. May I use the approach you posted above to check if it works? I would create a new pull request if successful. |
devongovett
commented
Oct 30, 2022
Sure, that would be great thanks! |
24e36e9 to
925383eCompareciffelia
commented
Oct 31, 2022
I just tried the This behavior doesn't seem to be documented clearly, but is described in react/react#22872 and react/react#18003 (comment). |
devongovett
commented
Oct 31, 2022
Hmm, this pattern is shown in the docs here: https://reactjs.org/docs/hooks-faq.html#how-to-create-expensive-objects-lazily |
ciffelia
commented
Nov 11, 2022
Although the docs implies https://codesandbox.io/s/loving-swirles-zc254v?file=/src/index.js import{useRef,StrictMode}from"react";import{createRoot}from"react-dom/client";constrootElement=document.getElementById("root");constroot=createRoot(rootElement);root.render(<StrictMode><App/></StrictMode>);letcnt=0;functionApp(){constref=useRef(null);if(ref.current===null){ref.current=`id-${cnt++}`;}console.log(ref.current);returnref.current;} |
LucasUnplugged
commented
Dec 9, 2022
@ciffelia: is the issue that the server-side correctly generates just one ID, and the client-side generates two? Maybe this is a "if you can't beat them, join them" situation: could modify the server-side to first generate a throw-away ID, then generate one that gets assigned? I guess ideally we'd want to also check if strict mode is disable before generating the first ID, if that's possible in the server-side (I'm assuming it is). |
ciffelia
commented
Dec 21, 2022
@LucasUnplugged I don't think that's possible. The SSR server sends rendered HTML to a browser immediately after the first rendering completed. There's no way to generate IDs after the first render. |
LucasUnplugged
commented
Dec 21, 2022
What I mean is, it sounds like the frontend runs the ID generation code twice, so the first instance has ID 2 in the frontend and ID 1 in SSR code. The second has ID 4 instead of ID 2, and so on. So in that case, I'm suggesting the ID generation func be run twice in the SSR logic as well, like: genID();// Throw awayconstactualID=genID;// Save this oneIf I understood correctly, the mismatch in IDs is deterministic, in that the first ID is always the same; the second is always the same; etc. The only difference is the frontend is doubling them up, in strict mode. |
@LucasUnplugged I was mistaken about the behavior of Strict Mode. Indeed, I think the idea you presented is possible. Unfortunately it seems to be impossible to check if the strict mode is enabled (at least in the render phase), so we need to add an option to enable that feature: <StrictMode><SSRProviderstrictMode={true}><App/></SSRProvider></StrictMode>Apart from that, I came up with an idea that allow users to let react-aria use importReactfrom'react'<SSRProvideruseId={React.useId}><App/></SSRProvider>This will not only solve the problem with strict mode, but also ensure that our Since both features are optional, there is less risk of breaking things. Those who are using React 18 may enable the latter feature, and others may choose the former. I would like to hear from maintainers before implementing them. |
brandonpittman
commented
Jan 23, 2023
Remix shipped their |

This commit implements a workaround for hydration error during SSR running in strict mode (#2231, #779).
The workaround uses
React.useId, which is introduced in React 18. On React 16 and 17, nothing changes with this commit (i.e. hydration error still occurs).✅ Pull Request Checklist:
📝 Test Instructions:
Note: I'm not sure if this test runs in react strict mode.
🧢 Your Project:
pixiv/charcoal