-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
69 lines (52 loc) · 1.54 KB
/
index.js
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
const HYDRATE = Symbol('HYDRATE');
const REMOVE = Symbol('REMOVE');
export const hydrate = () => ({ [HYDRATE]: true });
export const remove = (key) => ({ [REMOVE]: key });
const noop = () => {};
const mapObject = (mapper, obj) => {
const result = {};
Object.keys(obj).forEach((key) => {
result[key] = mapper(obj[key]);
});
return result;
};
let hydrating = false;
export default (
selectors = {},
{ storage = localStorage } = {},
) => ({ dispatch, getState }) => (next) => (action) => {
if (action[HYDRATE]) {
hydrating = true;
return Promise.all(
Object
.keys(selectors)
.map((key) => Promise.resolve(storage.getItem(key)) // Normalize into promise
.then((value) => {
const { load = noop } = selectors[key];
return load(value, { dispatch, getState });
})),
).then(() => { hydrating = false; });
}
if (action[REMOVE]) {
return Promise.resolve(storage.removeItem(action[REMOVE]));
}
if (hydrating) {
return next(action);
}
const prevState = getState();
const prevValues = mapObject(({ selector }) => selector(prevState), selectors);
next(action);
const state = getState();
if (state === prevState) { // selectors are pure functions of the state
return Promise.resolve();
}
return Promise.all(
Object.keys(selectors).map((key) => {
const { selector } = selectors[key];
const value = selector(state);
return (value === prevValues[key])
? undefined
: storage.setItem(key, value);
}),
);
};