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

Improve docs for atomWithStorage and persistence #805

Closed
dai-shi opened this issue Oct 27, 2021 · 17 comments · Fixed by #1221
Closed

Improve docs for atomWithStorage and persistence #805

dai-shi opened this issue Oct 27, 2021 · 17 comments · Fixed by #1221
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers help wanted Please someone help on this

Comments

@dai-shi
Copy link
Member

dai-shi commented Oct 27, 2021

#394 (comment) @jrobber

  • docs/guides/persistence.mdx should explain more about best practices with atomWithStorage
  • atomWithStorage docs should explain how to use non default storage like sessionStorage and AsyncStorage
  • atomWithStorage docs should explain how to use non JSON.parse/stringify serializer
  • atomWithStorage docs should explain how to type atoms
  • document options like delayInit atomWithStorage trouble with AsyncStorage #780 (comment)
  • document how to do validations and type guards
@dai-shi dai-shi added good first issue Good for newcomers help wanted Please someone help on this labels Oct 27, 2021
@dai-shi
Copy link
Member Author

dai-shi commented Oct 28, 2021

#806 (comment)

@ryandi-tiket Let's use this issue. Would you explain your problem with atomWithStorage in SSR?

@ryandi-tiket
Copy link

ryandi-tiket commented Oct 28, 2021

Mismatch server/client HTML.
With ClientOnly the warning disappears, but the layout shift is quite bad.

Plus we need to sanitize the localStorage value before it sets.

@dai-shi
Copy link
Member Author

dai-shi commented Oct 28, 2021

@ryandi-tiket Thanks! I see the issue is the mismatch warning.
Can you refer #780 and try delayInit option to see if it helps or not?

@ryandi-tiket
Copy link

Changing

const anAtom = atomWithStorage('ls_key', [])

to

const anAtom = atomWithStorage('ls_key', [], {
    ...createJSONStorage(() => localStorage),
  delayInit: true,
})

seems to have the same render behavior/timing as what I had going with onMount. But I need an extra "validation" process when mounting for the first time, which goes slightly like this:

const anAtom = atom([])

anAtom.onMount = (setValue) => {
  const possiblyInvalid = JSON.parse(localStorage.getItem('ls_key) ?? '[]')
  const validated = myValidator(possiblyInvalid)
  setValue(validated)
  localStorage.setItem('ls_key', JSON.stringify(validated))
}

I don’t think there exists an API for this in atomWithStorage yet yeah? Maybe I can customize getItem in 3rd argument of atomWithStorage, but I think it becomes unpredictable.

@dai-shi
Copy link
Member Author

dai-shi commented Oct 28, 2021

Good to hear that and thanks for the last mile.
Yes, my expectation is to customize getItem for validation or type guard.
We miss docs for this too.
By unpredictable, you mean it's not well established?
Another idea will be to extend createJSONStorage with validators, or even create a new function createJSONStorageWithValidator.

@ryandi-tiket
Copy link

ryandi-tiket commented Oct 28, 2021

By unpredictable I mean I’m ceding control and can’t be sure when/how often the validator will be called. Does jotai re-getItem from time to time? Will it do so for every instance of useAtom? If it’s computationally expensive, I’d only want it to run once on mount.

@dai-shi
Copy link
Member Author

dai-shi commented Oct 28, 2021

It runs just once:

const value = storage.getItem(key)

As you are already familiar with onMount, I'd highly encourage to read the code. It's fairly small (except for types.)

@ryandi-tiket
Copy link

Looks good. I think it just needs better docs, and perhaps slightly better ergonomics in this line:
...createJSONStorage(() => localStorage)

As for the validators, I’m thinking provide options that could be passed as 2nd argument to createJSONStorage, instead of another function createJSONStorageWithValidator.

const anAtom = atomWithStorage('ls_key', [], {
    ...createJSONStorage(() => localStorage, { onGetItem: (value) => myValidator(value), onSetItem: (value) => myValidator(value) }),
  delayInit: true,
})

@dai-shi
Copy link
Member Author

dai-shi commented Oct 29, 2021

If we add options to createJSONStorage, we can add delayInit there too.

createJSONStorage(() => localStorage, { delayInit: true })

I'm more than happy if you can help us on docs.

@ryandi-tiket
Copy link

delayInit moved from atomWithStorage option to createJSONStorage option? Will it be a backwards compatible change?

@dai-shi
Copy link
Member Author

dai-shi commented Oct 30, 2021

No, no. delayInit stays there. It's just createJSONStorage takes an option and transfers the option. It's just a syntax sugar to avoid { ...createJSONStorage(...), delayInit: true }, which you said less ergonomic.

@TwistedMinda
Copy link
Collaborator

TwistedMinda commented May 21, 2022

@dai-shi There are a few linked subjects already:

  • the loadable stuff and the "no suspense" stuff
  • the atomWithStorage utils stuff
  • the atomWithPending stuff
  • the persistence stuff
  • the async stuff

I'm trying to organize all that and they're already a few discussions/PR/issues about it.
In this issue, what's remaining to be done? It seems mostly good!
Especially the atomWithStorage examples. The persistence part has also been reworked recently.

Maybe we could close this one?

@dai-shi
Copy link
Member Author

dai-shi commented May 21, 2022

@TwistedMinda Can you check all bullet points in OP are covered?

@TwistedMinda
Copy link
Collaborator

@dai-shi yep to me it's kinda all good. Except the type guards which I don't know what are these :p

@dai-shi
Copy link
Member Author

dai-shi commented May 21, 2022

document how to do validations and type guards

This is to create a custom storage and make it type safe.
Usually, if you deserialize from string-based storage, you don't have types. Type guard is a runtime solution to make it type safe (just throw if unexpected...)
For now, nobody requested this, so let's leave it and revisit in the future.

@dai-shi
Copy link
Member Author

dai-shi commented Jun 9, 2022

  • atomWithStorage docs should explain how to use non default storage like sessionStorage and AsyncStorage

Looks like sessionStorage is missing? #1220

@dai-shi dai-shi reopened this Jun 9, 2022
@TwistedMinda
Copy link
Collaborator

@dai-shi Indeed, i'll take care of this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers help wanted Please someone help on this
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants