astoilkov / use-local-storage-state

React hook that persists data in localStorage
MIT License
1.09k stars 39 forks source link

Suspense error when using with another library #67

Closed nick-tw closed 5 months ago

nick-tw commented 6 months ago

I don't know if this is a Plasmic issue or use-local-storage-state. So I'm posting in both places.

I'm currently using plasmic. I have a blank page setup. I then added your sample code from the documentation.

When the page renders, I get a suspense error: 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.

Commenting out Plasmic and putting <div>Test Page</div>, the page renders fine. Commenting out use-local-storage-state, the page renders fine.

Leaving both in, causes the error.


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>
  )
}
astoilkov commented 6 months ago

Can you provide a link to the issue you created in Plasmic (if it's public)? This way I can keep track of progress on the other end.

I suspect that useLocalStorageState is triggering an update which triggers a <Suspense> component re-render (the <Suspense> is likely inside <PlasmicComponent>. I'm not familiar with Plasmic but I would guess that moving the useLocalStorageState hook inside of the <PlasmicComponent> rather than outside will fix the error.

nick-tw commented 6 months ago

Issue here: https://forum.plasmic.app/t/suspense-error-using-third-party-use-local-storage-state/6975

Yes, I believe you're correct. This started to happen when I was moving the states up to the parent component.

nick-tw commented 5 months ago

I've eventually created contexts and wrapped it around the component which side steps the issue. Closing for now.

nick-tw commented 5 months ago

I'm reopening this. My previous work around with context suddenly started throwing a suspense error.

I've setup a basic page here: https://github.com/nick-tw/localstoragesynctest

You can clone, npm i, and then run npm run dev

It appears that using an array as defaultValue is causing a suspense error like so:

//this causes a Suspense error
  const [test2, setTest2] = useLocalStorageState(`test2`, { defaultValue: [] })

However, defining a default value of empty string or boolean works fine

const [test1, setTest1] = useLocalStorageState("test1", {
    defaultValue: false,
  })

Of course, when I comment out the <PlasmicRootProvider>, the defaultValue array works fine so perhaps this is still a Plasmic problem? I just found that it was interesting that it only happens with arrays with useLocalStorageState. If there's any light you can shed, that would be appreciated.

astoilkov commented 5 months ago

This is what causes it: CleanShot 2024-04-06 at 20 07 56@2x

The two values aren't equal === and thus React triggers a re-render.

I think that if I fix it it will also improve performance because it will skip a re-render on page load when you have a defaultValue that's not a primitive value. Give me some time to think about it.

Thanks for getting back and reopening.

astoilkov commented 5 months ago

I fixed it. However, I haven't written tests for it and I don't like the implementation very much. I will fix these before I make a new release.

Again, thanks!

nick-tw commented 5 months ago

Thanks!

However, when I add

"use-local-storage-state": "github:astoilkov/use-local-storage-state#8f079e750a90277170d947c440baa09b3b94d2f4",

In my package.json, it seems to only pull 3 files (license, package.json, readme.md).

astoilkov commented 5 months ago

Yeah, you can't do that because the TypeScript isn't transpiled. It gets transpiled before publishing to NPM. I'm not sure what the most elegant solution to fix this is. Maybe fork?

astoilkov commented 5 months ago

Hey, as I started improving the implementation and writing tests I figured out something. With my fix I fixed the problem but only when there is nothing in localStorage. If there is something for that key, it will throw again, and this is something I can't fix in my library (I think). That points to the problem probably being in Plasmic.

nick-tw commented 5 months ago

I did end up using your latest update and it seems to fix the error but have not fully tested yet.

Thanks for trying anyways. I'll figure something out if it comes back.