"Error: This Suspense boundary received an update before it finished hydrating" using third party use-local-storage-state

I’m trying to use use-local-storage-state to persist data to localStorage with this Next.js project use-local-storage-state - npm

Using “@plasmicapp/loader-nextjs”: “^1.0.363”, “use-local-storage-state”: “^19.2.0”.

I have a blank “random” page in plasmic. Code here:

import React from "react"
import useLocalStorageState from "use-local-storage-state"
import {
  PlasmicComponent,
  PlasmicRootProvider
} from "@plasmicapp/loader-nextjs"
import { PLASMIC } from "../plasmic-init"


export default function PageComponent(props) {
  const [todos, setTodos] = useLocalStorageState('todos', {
    defaultValue: ['buy avocado', 'do 50 push-ups']
})
  return (
    <PlasmicRootProvider loader={PLASMIC} prefetchedData={props.plasmicData}>
      <PlasmicComponent
        component='random'
        componentProps={{

        }}
      />
    </PlasmicRootProvider>
  )
}

It’s giving " Unhandled Runtime Error 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."

Removing Plasmic components and just rending <div>hi</div> is fine. Removing “use-local-storage-state” and just rendering Plasmic components is fine.

There’s some sort of conflict here.

Here’s a basic setup:

It seems to be specific to using an array for defaultValue in useLocalStorageState

However, when I comment out PlasmicRootProvider and use a basic

, it works. When I comment out useLocalStorageState and leave PlasmicRootProvider, it works. I cannot use both useLocalStorageState and PlasmicRootProvider and the same time.

Hi, the minimal code to reproduce the error in this case is:

import * as React from "react";

function Homepage() {
  React.useSyncExternalStore(
    (onStoreChange) => {
      return () => null;
    },
    () => [],
    () => [],
  );

  return (
    <React.Suspense>
      <div>hi</div>
    </React.Suspense>
  );
}

export default Homepage;

Since useSyncExternalStore is being used by use-local-storage-state and React.Suspense is used by @plasmicapp/loader-*.

This was described in Bug: Error due to `serverSnapshot` and `snapshot` mismatch in `useSyncExternalStore` when used with `Suspense` SSR · Issue #26318 · facebook/react · GitHub and it should be fixed in a future release of React.

As a quick fix, in Plasmic, we allow you to remove the React.Suspense by using the flags disableLoadingBoundary={true} and disableRootLoadingBoundary={true} in your <PlasmicRootProvider/> instance.

In your example:

<PlasmicRootProvider
   loader={PLASMIC}
   prefetchedData={props.plasmicData}
   disableLoadingBoundary={true}
   disableRootLoadingBoundary={true}
>

You should also not use the LoadingBoundary component in the Studio to avoid adding additional React.Suspense.

But there are some consequences to that. The main reason we have React.Suspense is to power Backend data integrations | Learn Plasmic usage in Plasmic projects. So, by disabling it, you may face unintended issues if you are using Plasmic data integrations to perform data fetching in your application. If you solely fetch data in SSG or SSR, it should be fine to disable it from your client.

This error seems to be visible in other combinations of hooks in a nondeterministic way, and it seems to have similar reasons as in the linked issue.