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

feat(util): atomWithStorage #394

Merged
merged 7 commits into from
May 9, 2021
Merged

feat(util): atomWithStorage #394

merged 7 commits into from
May 9, 2021

Conversation

sandren
Copy link
Collaborator

@sandren sandren commented Mar 30, 2021

There are examples of how to add persistence to individual atoms in the docs, but I would like to create a robust atomWithStorage utility that covers most use cases, including localStorage or sessionStorage for React as well as AsyncStorage for React Native. Also note that the stored value is intentionally populated in the onMount method rather than the base atom() initialization to support atomWithStorage usage in SSR contexts such as Next.js and Gatsby. The first commit is a work in progress.

Progress

@dai-shi dai-shi marked this pull request as draft March 30, 2021 14:40
@dai-shi
Copy link
Member

dai-shi commented Mar 30, 2021

Thanks for opening this up! I expect this is going to be a good one and thus taking time. Please bare with me. No ETA.

import type { SetStateAction } from '../core/types'

export function atomWithStorage<Value>(key: string, initialValue: Value) {
type Update = SetStateAction<Value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we accept function update? If so, L24-L26 should be implemented so. There's no magic.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be:

    (get, set, update: Update) => {
      const newValue = typeof update === 'function' ? update(get(baseAtom)) : update
      set(baseAtom, newValue)
      window.localStorage.setItem(key, JSON.stringify(newValue))
    }

@codesandbox-ci
Copy link

codesandbox-ci bot commented Mar 30, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 77e45b6:

Sandbox Source
React Configuration
React Typescript Configuration

@dai-shi
Copy link
Member

dai-shi commented Mar 30, 2021

The WIP version looks actually good, and is worth a guide in docs.

To make if a flexible util, we want to abstract the storage api.

type Storage<Value> = {
  getItem: (key: string) => Value | Promise<Value>
  setItem: (key: string, newValue: Value) => void | Promise<void>
}

export function atomWithStorage<Value>(key: string, default: Value, getStorage?: () => Storage<Value>): PrimitiveAtom<Value>

@vercel
Copy link

vercel bot commented Apr 5, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/pmndrs/jotai/GqoydTYPnoGaaqDbFqTbv4X9sDWt
✅ Preview: https://jotai-git-fork-sandren-feat-atom-with-storage-pmndrs.vercel.app

@Aslemammad
Copy link
Member

@sandren Wow, I really loved this idea, Hope it gets released soon so I can use it in my new project.

@dai-shi dai-shi mentioned this pull request Apr 13, 2021
49 tasks
@sandren sandren marked this pull request as ready for review May 9, 2021 13:53
@dai-shi dai-shi merged commit 963eeb9 into pmndrs:master May 9, 2021
@ghmeec
Copy link

ghmeec commented May 9, 2021

this is awesome, i haven't been able to test in RN environment, would there be a problem since getItem and setItem methods are async?

@dai-shi
Copy link
Member

dai-shi commented May 9, 2021

@ghmeec We hoped this would support AsyncStorage, but not thoroughly tested. Would you give it a try?

@jrobber
Copy link

jrobber commented Oct 27, 2021

@dai-shi Awesome work here!

I can confirm that atomWithStorage works on react-native if your atom is a string. It does appear to any JSON.stringify or JSON.parse.

To get other types I had to dig through Jotai code until I found createJSONStorage.
I was then able to get other types working like this.

export const userAtom = atomWithStorage<User | null>('USER', null, createJSONStorage(()=> AsyncStorage));

For me, this is acceptable. I recommend maybe just adding it to the docs.

@dai-shi
Copy link
Member

dai-shi commented Oct 27, 2021

Yeah, we don't have enough docs about atomWithStorage...

@thinkdj
Copy link

thinkdj commented Jan 1, 2023

Often, we need to store sensitive data like a token or basic authentication info for persistence, and storing such data plainly to localStorage seems less secure. Provision for a custom hook for encrypt/decrypt would be great to see

@dai-shi
Copy link
Member

dai-shi commented Jan 2, 2023

You should be able to customize storage.

@thinkdj
Copy link

thinkdj commented Jan 2, 2023

You should be able to customize storage.

Ah! Missed this. Thank you.

Reference for others: Customizing storage: Docs & sample.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants