question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Bug: `startTransition` not working with `useSyncExternalStore`

See original GitHub issue

SSR content shows a fallback during hydration if there has been an update to an external state, even if wrapped with startTransition.

React version: 18.2.0

Steps To Reproduce

  1. Create a basic SSRed React application that would have suspensible content.
  2. Create an external store and read its values using useSyncExternalStore in the same component which has suspensible content.
  3. Update this external store on the application mount(while hydrating), and wrap this update with startTransition;

Link to code example: https://codesandbox.io/s/react-18-starttransition-not-working-with-usesyncexternalstore-4pxygp

The current behavior

The content shows a fallback while the update is done.

The expected behavior

The content should not show a fallback, but rather update without showing it.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:12 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
SuperOleg39commented, Sep 20, 2022

@stanislav-halyn hi!

I recently met a similar problem, and found answer here - https://github.com/facebook/react/issues/24476#issuecomment-1127800350

In this example, you don’t pass props from user store to suspended component directly. So, just memoize this suspended block:

export default function Layout() {
  const user = useUser();

  useEffect(() => {
    startTransition(() => {
      User.updateUser({
        data: {
          firstName: "Steve"
        }
      });
    });
  }, []);

  const memoizedContent = useMemo(
    () => (
      <Suspense fallback={<Loader />}>
        <LazyContent />
      </Suspense>
    ),
    []
  );

  return (
    <div>
      <header>this is header</header>
      <br />
      <p>user data: {JSON.stringify(user.data)}</p>.
      <br />
      <main>{memoizedContent}</main>
    </div>
  );
}
1reaction
gaearoncommented, Sep 22, 2022

Note there’s also another option, which is to not SSR LazyContent either. I.e. you can always emit fallback on the server. Then it won’t be in HTML (which is unfortunate), but you’ll also avoid this problem. If you decide to go that route, you need to throw an Error on the server only from inside the part you want to make client-only (like this lazy content). When you throw an Error on the server, with streaming SSR, the error won’t fail the render. Instead, the server will emit the Suspense fallback. The client will retry rendering when the code loads. During retry, you won’t throw, so lazy content will be able to show up. The error will be reported in the console, but you can pass onRecoverableError with hydrateRoot options, detect your custom Error (e.g. by its message) and silence it because it’s expected. This is a supported way to render client-only content.

Read more comments on GitHub >

github_iconTop Results From Across the Web

useSyncExternalStore - React Docs
Troubleshooting · I'm getting an error: “The result of getSnapshot should be cached” · My subscribe function gets called after every re-render.
Read more >
React 18 is out! - Meteor forums
We are now encountering a problem wherein a page is being redirected to another page in SSR. This happens when the app is...
Read more >
React 18 : Concurrency, Automatic Batching, Transitions ...
The problem with asynchronous transactions is once you initiate an ... With React 18, developers can use start transition API inside an ...
Read more >
React 18 for External Store Libraries - YouTube
An error occurred while retrieving sharing information. Please try again later. 0:00. 0:00 / 19:22• Live. •. •. Scroll for details ...
Read more >
React 18, React Redux 8, and TypeScript: What you need to ...
This is where the startTransition API comes in. ... LogRocket tells you the most impactful bugs and UX issues actually impacting users in ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found