-
Notifications
You must be signed in to change notification settings - Fork 40
/
index.ts
90 lines (78 loc) · 2.1 KB
/
index.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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { AtomEffect } from 'recoil'
export interface PersistStorage {
setItem(key: string, value: string): void | Promise<void>
getItem(key: string): null | string | Promise<string>
}
export interface PersistConfiguration {
key?: string
storage?: PersistStorage
}
/**
* Recoil module to persist state to storage
*
* @param config Optional configuration object
* @param config.key Used as key in local storage, defaults to `recoil-persist`
* @param config.storage Local storage to use, defaults to `localStorage`
*/
export const recoilPersist = (
config: PersistConfiguration = {},
): { persistAtom: AtomEffect<any> } => {
const { key = 'recoil-persist', storage = localStorage } = config
if (typeof window === 'undefined') {
return {
persistAtom: () => {
},
}
}
const persistAtom: AtomEffect<any> = ({ onSet, node, trigger, setSelf }) => {
if (trigger === 'get') {
const state = getState()
if (typeof state.then === 'function') {
state.then((s) => {
if (s.hasOwnProperty(node.key)) {
setSelf(s[node.key])
}
})
}
if (state.hasOwnProperty(node.key)) {
setSelf(state[node.key])
}
}
onSet((newValue) => {
const state = getState()
state[node.key] = newValue
setState(state)
})
}
const getState = (): any => {
const toParse = storage.getItem(key)
if (toParse === null || toParse === undefined) {
return {}
}
if (typeof toParse === 'string') {
return parseState(toParse)
}
if (typeof toParse.then === 'function') {
return toParse.then(parseState)
}
return {}
}
const parseState = (state: string) => {
try {
return JSON.parse(state)
} catch (e) {
console.error(e)
return {}
}
}
const setState = (state: any): void => {
try {
//TODO for React Native `AsyncStorage`, we should be using `mergeItem`
// to merge existing stringified object with new one
storage.setItem(key, JSON.stringify(state))
} catch (e) {
console.error(e)
}
}
return { persistAtom }
}