Storage hook `undefined` during initial render
Hey! I'm using the
useStorage
hook and noticed that during the initial render, it is undefined
(default value) and then gets populated with the value from storage. I understand why this is the case (async data store vs sync rendering), however is there any way we can make it so that all storages are loaded before the rest of the application shows (i.e. no initial render with default values)?35 Replies
Doc: https://docs.plasmo.com/framework/storage#hook-api-for-react-components
Source: https://github.com/PlasmoHQ/storage/blob/main/src/hook.ts
Jotai has this idea of a preloader: https://jotai.org/docs/guides/persistence#with-suspense but I'm not sure how we can make it work with
useStorage
You can do
value ? <Loading> : <ActualStuff>
And chain them, fair enough. Lemme give that a shot!
This is a bit trickier than I thought.
useStorage('favoriteNumber', (value) => (value === undefined ? 10 : value));
. Initially this will render (and persist) the value 10
. If the user then modifies the value in the settings to 20
and opens up the extension again, they will see a flash of 10
before 20
. And we can't really do a null
check because theres a default value
I suppose I could try useStorage('favoriteNumber')
and useEffect
where if(!favoriteNumber) setStorage(10)
but I'm not sure if that would cause issuesinteresting
maybe we can add something to the 3rd return value of the hook
so the first 2 values model after useState
the 3rd value provides more than that
maybe we can add a
isHydrated
bool in the 3rd one
and then only if the value is hydrated would we set that to true
what do you think?
bc useStorage tries to be an API-replica of useState, the concept of rehydration doesn't quite sync up (since useState hydration is supposedly synced with the runtime and renderer).Sorry just got back, that’s exactly the kind of solution I was thinking!
I was toying around with suspense but couldn’t figure it out
But that would also be an alternative cool solution
Ah I’m too slow, I see you already implemented it
Thank you! I’ll let you know if I find any problems
oh yeah I actually
just released it lol
try out the latest version and lmk how it goes xD
Is there a way to return this promise as well? https://github.com/PlasmoHQ/storage/blob/main/src/hook.ts#L61
GitHub
storage/hook.ts at main · PlasmoHQ/storage
💾 Safely store data and share it across your extension - storage/hook.ts at main · PlasmoHQ/storage
I ask because I was messing around to see if I can implement suspense so I dont have to check for
isHydrated
in every location I use the store
https://www.youtube.com/watch?v=PtoQpVOQ5Ew
Seems like you need to throw a promise and react re-renders when the promise resolvesPR welcome :p
Let me try 🙂
in term of is there a way, I wonder
we can store that promise in a ref and expose it in the 3rd arg?
I wonder if its as simple as passing
suspense = true
as a prop to the hook and then if (suspense) throw
on that line
Ah its in the useEffect, nvmI ask because I was messing around to see if I can implement suspense so I dont have to check for isHydrated in every location I use the storeOne way to solve this is to use a context/provider
Can I clone only the storage and link it or do I have to do the whole suite?
Yeah but suspense is cooler 😛
I wonder if it works with parcel tho
since suspense is dynamic import
and the current bundler atm is actually pretty shoddy at dynamic resolving atm, more so for extension since they usually expects a single bundle code
(this is something we will need to improve along the line and think about - is there a way to do React server component/suspense in extension? <- this is a new frontier for next year imo)
Even in NextJS, they had to make their own
dynamic
function to handle dynamic import since the default async import just sucks and doesn't work in their runtime/isomorphic
so very likely Plasmo will have to adopt a similar strategy if it wanted to support suspense/dynamic import