/
utils.js
128 lines (90 loc) · 3.28 KB
/
utils.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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { useReducer, useEffect, useLayoutEffect } from 'react';
import invariant from 'invariant';
import isPlainObject from 'is-plain-object';
export { isPlainObject };
export const isString = str => typeof str === 'string';
export const isFunction = fn => typeof fn === 'function';
// export const isObject = obj => typeof obj === 'object' && !Array.isArray(obj);
export const isPromise = obj => obj instanceof Promise && isFunction(obj.then);
// @see https://github.com/koajs/compose/
export function compose(funcs) {
invariant(Array.isArray(funcs), 'Middleware stack must be an array!');
funcs.forEach(fn => {
invariant(isFunction(fn), 'Middleware must be composed of functions!');
});
return function goNext(ctx, next) {
let index = -1;
function dispatch(i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'));
index = i;
let fn = funcs[i];
if (i === funcs.length) fn = next;
if (!fn) return Promise.resolve();
try {
return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err);
}
}
return dispatch(0);
};
}
export function checkModels(props = {}) {
const { model, models } = props;
invariant(model || models, 'Provider props `model` or `models` required!');
if (models) {
invariant(Array.isArray(models), 'models should be array!');
invariant(models.length >= 1, 'should provide at last one model!');
// for (const m of models) checkModel(m);
for (let i = 0; i < models.length; i++) {
checkModel(models[i]);
}
return;
}
checkModel(model);
}
function checkModel(model) {
invariant(isPlainObject(model), 'model should be plain object!');
const { name, state, actions /* , middlewares */ } = model;
invariant(name, 'model name is required!');
invariant(typeof name === 'string', 'model name should be string!');
if (state) invariant(isPlainObject(state), 'model state should be plain object!');
if (actions) invariant(isPlainObject(actions), `model actions should be plain object!`);
// if (middlewares) checkMiddlewares(middlewares);
}
export function checkMiddlewares(middlewares) {
invariant(Array.isArray(middlewares), 'typeof middlewares should be array!');
}
export const useIsomorphicLayoutEffect =
typeof window !== 'undefined' ? useLayoutEffect : useEffect;
export function useForceRender() {
return useReducer(c => c + 1, 0)[1];
}
export function tryClone(value) {
if (isPlainObject(value)) return JSON.parse(JSON.stringify(value));
if (Array.isArray(value)) return value.slice();
return value;
}
const hasOwn = Object.prototype.hasOwnProperty;
function is(x, y) {
if (x === y) {
return x !== 0 || y !== 0 || 1 / x === 1 / y;
}
return x !== x && y !== y;
}
// @see react-redux
export function shallowEqual(objA, objB) {
if (is(objA, objB)) return true;
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) return false;
for (let i = 0; i < keysA.length; i++) {
if (!hasOwn.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
return false;
}
}
return true;
}