-
-
Notifications
You must be signed in to change notification settings - Fork 639
/
Copy pathatomWithStorage.ts
59 lines (52 loc) · 1.39 KB
/
atomWithStorage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { atom, PrimitiveAtom } from 'jotai'
import type { SetStateAction } from '../core/types'
type Storage<Value> = {
getItem: (key: string) => Value | Promise<Value>
setItem: (key: string, newValue: Value) => void | Promise<void>
}
const defaultStorage: Storage<unknown> = {
getItem: (key) => {
const storedValue = localStorage.getItem(key)
if (storedValue === null) {
throw new Error('no value stored')
}
return JSON.parse(storedValue)
},
setItem: (key, newValue) => {
localStorage.setItem(key, JSON.stringify(newValue))
},
}
export function atomWithStorage<Value>(
key: string,
initialValue: Value,
storage: Storage<Value> = defaultStorage as Storage<Value>
): PrimitiveAtom<Value> {
const getInitialValue = () => {
try {
return storage.getItem(key)
} catch {
return initialValue
}
}
const baseAtom = atom(initialValue)
baseAtom.onMount = (setAtom) => {
const value = getInitialValue()
if (value instanceof Promise) {
value.then(setAtom)
} else {
setAtom(value)
}
}
const anAtom = atom(
(get) => get(baseAtom),
(get, set, update: SetStateAction<Value>) => {
const newValue =
typeof update === 'function'
? (update as (prev: Value) => Value)(get(baseAtom))
: update
set(baseAtom, newValue)
storage.setItem(key, newValue)
}
)
return anAtom
}