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

Bug: Error due to serverSnapshot and snapshot mismatch in useSyncExternalStore when used with Suspense SSR #26318

Closed
mgiedrius opened this issue Mar 6, 2023 · 4 comments
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug

Comments

@mgiedrius
Copy link

mgiedrius commented Mar 6, 2023

React version: 18.2.0

Steps To Reproduce

  1. Use Suspense SSR and useSyncExternalStore in the same component.
  2. Ensure that the serverSnapshot and snapshot in useSyncExternalStore are different.
  3. Console prints:

Uncaught Error: This Suspense boundary received an update before it finished hydrating. This caused the boundary to switch to client rendering. The usual way to fix this is to wrap the original update in startTransition.

Link to code example: https://codesandbox.io/s/usesyncexternalstore-suspense-bug-lyoc03?file=/src/App.js:49-69

The current behavior

Error message appears:

Uncaught Error: This Suspense boundary received an update before it finished hydrating. This caused the boundary to switch to client rendering. The usual way to fix this is to wrap the original update in startTransition.

Due to a mismatch between serverSnapshot and snapshot when using Suspense and useSyncExternalStore in the same component.

The expected behaviour

The error doesn't appear:

  • if the serverSnapshot and snapshot are identical.
  • if the useSyncExternalStore has a mismatch between serverSnapshot and snapshot and is used in a component without a Suspense boundary.

I assume the expected behaviour should be: no error when useSyncExternalStore is used with Suspense in the same component.

Question

Maybe there is a possible temporary patch for this issue?

@mgiedrius mgiedrius added the Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug label Mar 6, 2023
@mgiedrius mgiedrius changed the title Bug: Error due to serverSnapshot and snapshot mismatch in useSyncExternalStore and Suspense Bug: Error due to serverSnapshot and snapshot mismatch in useSyncExternalStore when used with Suspense Mar 6, 2023
@mgiedrius mgiedrius changed the title Bug: Error due to serverSnapshot and snapshot mismatch in useSyncExternalStore when used with Suspense Bug: Error due to serverSnapshot and snapshot mismatch in useSyncExternalStore when used with Suspense SSR Mar 6, 2023
@eps1lon
Copy link
Collaborator

eps1lon commented Mar 9, 2023

I'm not seeing any error when opening https://codesandbox.io/s/usesyncexternalstore-suspense-bug-lyoc03?file=/src/App.js:217-241.

Did you maybe change the codesandbox in the meantime?

@mgiedrius
Copy link
Author

mgiedrius commented Mar 9, 2023

@eps1lon Hi, I haven't updated the code in Codesandbox. I'm not entirely sure why the error message isn't showing up in the Codesandbox environment's console maybe it has something to do with how this error is logged, but you can still see the error by checking out the browser console. By looking at the Codesandbox environment's browser console or by opening the direct browser view link: https://lyoc03.sse.codesandbox.io/. Here's a screenshot if that helps:
image

@eps1lon
Copy link
Collaborator

eps1lon commented Mar 9, 2023

Ah gotcha, error didn't display in codesandbox console.

This was fixed in #25692. The next stable release should have this. In the meantime, you can verify it by using react@next, @react-dom@next

@eps1lon eps1lon closed this as completed Mar 9, 2023
@mgiedrius
Copy link
Author

mgiedrius commented Mar 12, 2023

@eps1lon Tested it in the @next version. The error logging is fixed but the Suspense SSR component behaviour looks unexpected.

React version: 18.3.0-next-a8875eab7-20230310

Steps To Reproduce

  1. Use Suspense SSR and useSyncExternalStore in the same component.
  2. Ensure that the serverSnapshot and snapshot in useSyncExternalStore are different.
  3. Suspended component on the client side fully rerenders. Falls into a fallback state and then renders its content.

Link to code example: https://codesandbox.io/p/sandbox/usesyncexternalstore-suspense-bug-forked-drm325

The current behavior

The suspended component on the client side fully rerenders. Falls into a fallback state and then renders its content. Due to a mismatch between serverSnapshot and snapshot when using Suspense and useSyncExternalStore in the same component.

The expected behaviour

The suspended component doesn't do a full rerender(falls into a fallback state and then renders its content):

  • if the serverSnapshot and snapshot are identical.
  • if the useSyncExternalStore has a mismatch between serverSnapshot and snapshot and is used in a component without a Suspense boundary.

I assume the expected behaviour should be: the suspended component shouldn't do a full rerender(fall into a fallback state and then render its content) when useSyncExternalStore is used with Suspense in the same component. I assume it shouldn't fall into a fallback state it should just do a rerender.

Additional context

One use case when snapshot and serverSnapshot may be different:
The latest version of the react-redux library under the hood uses useSyncExternalStore. For example, if we have 2 different hydrateRoot entries for header and for body and we need them to share the same redux store. One issue that occurs with this setup is that if the header is hydrated earlier than the body the header will start firing store updates while the body is still hydrating and this will cause serverSnapshot and snapshot to be different while the body is still hydrating and because of this suspended SSR components will fall into the fallback state if redux state selector and Suspense boundary are used in the same component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug
Projects
None yet
Development

No branches or pull requests

2 participants