-
Notifications
You must be signed in to change notification settings - Fork 47k
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
Bug: Incorrect Hydration Mismatch Detection during Suspense - "Hydration failed because the initial UI does not match what was rendered on the server." #24384
Comments
Minimal repro without Next.js: https://codesandbox.io/s/compassionate-night-uzyxv1?file=/src/App.js |
Seems like a bug. Weird that I can't repro this in tests. |
Hi, I have seen this error lots of times in #23381. The issue was closed because Dom-Patching executed by React is not an alternative in React 18 anymore. The problem with a sibling component following a suspending component seems quite related to what follows the suspending component can be seen as the mismatch itself. In my opinion, when a suspender alike component is involved, it is similar if you take direct action patching the DOM now on the client-side, on user code because react doesn`t do this not anymore. The following findings ask if the suspected bug is related to the following interpretation.
It seems it is impossible to prune on the client side before starting hydration. The only way possible is involving an effect and a state. Even with a suspense boundary in place it is not possible. Observation The throw statement in popHydrationState ensures that an error is thrown if there are still actual differences between the server and client that have not been previously resolved through client intervention in a Suspense boundary. I ask you to revisit the comments about the repetitive throw events in the samples. The function tryToClaimNextHydratableInstance gets invoked inside the update functions of
The base question is if the throw statements in the function tryToClaimNextHydratableInstance are too early and unnecessary; the second sample extracted from popHydrationState throws them again and mentions an interesting comment. Note: Question???
The function popHydrationState gets called after tryToClaimNextHydratableInstance in the respective update functions from above. I copied the relevant section of the popHydrationState function. The comment in the code makes me wonder if this is the only position where the throw of a hydration mismatch makes sense. As mentioned above, the popHydrationState gets executed after the update functions for Host, Suspense, and Text.
Thx! |
If a components suspends during hydration we expect there to be mismatches with server rendered HTML but we were not always supressing warning messages related to these expected mismatches
If a components suspends during hydration we expect there to be mismatches with server rendered HTML but we were not always supressing warning messages related to these expected mismatches
If a components suspends during hydration we expect there to be mismatches with server rendered HTML but we were not always supressing warning messages related to these expected mismatches
* Add failing test case for #24384 If a components suspends during hydration we expect there to be mismatches with server rendered HTML but we were not always supressing warning messages related to these expected mismatches * Mark hydration as suspending on every thrownException previously hydration would only be marked as supsending when a genuine error was thrown. This created an opportunity for a hydration mismatch that would warn after which later hydration mismatches would not lead to warnings. By moving the marker check earlier in the thrownException function we get the hydration context to enter the didSuspend state on both error and thrown promise cases which eliminates this gap. * Fix failing test related to client render fallbacks This test was actually subject to the project identified in the issue fixed in this branch. After fixing the underlying issue the assertion logic needed to change to pick the right warning which now emits after hydration successfully completes on promise resolution. I changed the container type to 'section' to make the error message slightly easier to read/understand (for me) * Only mark didSuspend on suspense path For unknown reasons the didSuspend was being set only on the error path and nto the suspense path. The original change hoisted this to happen on both paths. This change moves the didSuspend call to the suspense path only. This appears to be a noop because if the error path marked didSuspend it would suppress later warnings but if it does not the warning functions themsevles do that suppression (after the first one which necessarily already happened) * gate test on hydration fallback flags * refactor didSuspend to didSuspendOrError the orignial behavior applied the hydration warning bailout to error paths only. originally I moved it to Suspense paths only but this commit restores it to both paths and renames the marker function as didThrow rather than didSuspend The logic here is that for either case if we get a mismatch in hydration we want to warm up components but effectively consider the hydration for this boundary halted * factor tests to assert different behavior between prod and dev * add DEV suffix to didSuspendOrError to better indicate this feature should only affect dev behavior * move tests back to ReactDOMFizzServer-test * fix comment casing * drop extra flag gates in tests * add test for user error case * remove unnecessary gate * Make test better it now has an intentional client mismatch that would error if there wasn't suppression brought about by the earlier error. when it client renders it has the updated value not found in the server response but we do not see a hydration warning because it was superseded by the thrown error in that render
Please see my comment in the PR: #24404 (comment) |
In my opinion, when a suspender alike component is involved, it is similar if you take direct action patching the DOM on the client-side, within your own code, because React does not do this anymore.
BUT
functions extracted from Reacts source code #24384 (comment). What do you think? |
@xiel can you confirm the fix in #24480 addresses your concern. Here is a slightly modified version of the original repro on codesandbox using the build from that PR and I believe it is doing what you expect: https://codesandbox.io/s/trusting-buck-2j21to?file=/package.json |
@gnoff Looks good, thanks so much for working on this! 🤟 |
Hi, will the fix be on 18.1.1 / 18.2.0? I see the issue still persist on 18.1.0 note:
also solved the issue... |
The plan is to release it in 18.2. |
This comment was marked as resolved.
This comment was marked as resolved.
It's expected that there is a development-only remount if your code is running in Strict Mode. https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-strict-mode |
When the Login token is undefined that time "Hydration failed because the initial UI does not match what was rendered on the server " is coming just remove the token from local storage |
React version: 18.0.0
Steps To Reproduce
Reproductions in CodeSandbox:
The current behavior
The expected behavior
OR
The text was updated successfully, but these errors were encountered: