-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcreate.ts
175 lines (153 loc) · 5.14 KB
/
create.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
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
/**
* 实现全局的 actions
*
* 1. 订阅函数
* 2. 在其他页面执行函数
* 3. 不需要用户手动消除订阅,会根据组件自动销毁而销毁
*/
interface Actions {
[type: string]: Set<Function>;
}
type ActionsUpdateCallback = (actions: Actions) => void;
type ActionCallback = (...params: any[]) => Promise<any[]>
type DataType = 'Object' | 'Array' | 'Set'
function create() {
// 当前所有的 actions
let actions: Actions = {};
// 当 actions 变动后,会触发 updateActions
const updateActions: Record<number, ActionsUpdateCallback> = {};
// 每个 action 都会分配唯一的 key
let serialNumber = 0;
function numberHandle() {
const lastNumber = serialNumber;
serialNumber += 1;
return lastNumber;
}
function useSubscribe() {
// 保存当前组件的所有订阅
const currentAddCallbackRef = useRef(new Set<Function>());
useEffect(() => {
return () => {
// 组件销毁时,删除当前组件的所有订阅
Object.values(actions).forEach((callbacks) => {
const sets = currentAddCallbackRef.current;
sets.forEach((key) => {
if (callbacks.has(key)) {
callbacks.delete(key);
}
});
});
currentAddCallbackRef.current = new Set<Function>();
};
}, []);
return useCallback(
(type: string, callback: Function) => {
// 当原本订阅不存在时,创建一个新的 Set
if (!actions[type]) {
actions[type] = new Set<Function>();
}
actions[type].add(callback);
currentAddCallbackRef.current.add(callback);
actions = { ...actions };
// 触发更新
Object.values(updateActions).forEach((action) => {
action(actions);
});
},
[]
);
}
function useAction(funCallback: (actions: Actions) => Set<Function>): ActionCallback;
function useAction(funCallback: (actions: Actions) => Set<Function>[]): ActionCallback[];
function useAction(funCallback: (actions: Actions) => Record<string, Set<Function>>): Record<string, ActionCallback>;
function useAction(funCallback: (actions: Actions) => any): any {
const [typeActions, setTypeActions] = useState(funCallback(actions));
// 返回值类型
const returnType = useMemo(() => typeofData(typeActions), [typeActions]);
// 得到每一种类型的默认值
const initValRef = useRef<any>(getInitTypeVal(returnType));
// 每个 action 都会分配唯一的 key
const currentN = useRef(numberHandle());
useEffect(() => {
initValRef.current = getInitTypeVal(returnType);
}, [funCallback, returnType]);
useEffect(() => {
const uniqueKey = currentN.current;
updateActions[uniqueKey] = (newActions) => {
let newTypeActions;
if (returnType === 'Object') {
newTypeActions = Object.assign(
initValRef.current,
funCallback(newActions)
);
} else if (returnType === 'Array') {
initValRef.current.push(...funCallback(newActions));
newTypeActions = initValRef.current;
} else {
newTypeActions = funCallback(newActions);
}
if (newTypeActions !== typeActions) {
setTypeActions(newTypeActions);
}
};
return () => {
initValRef.current = getInitTypeVal(returnType);
delete updateActions[uniqueKey];
};
}, [returnType, funCallback, typeActions]);
return useMemo<any>(() => {
switch (returnType) {
case 'Set':
return trigger.bind(null, typeActions);
case 'Object': {
const obj: Record<string, Function> = {};
Object.entries(typeActions).forEach(([key, tempTypeActions]) => {
obj[key] = trigger.bind(null, tempTypeActions);
});
return obj;
}
case 'Array':
return typeActions.map((tempTypeActions: any) =>
trigger.bind(null, tempTypeActions)
);
default:
return () => {}
}
}, [returnType, typeActions]);
}
return { useSubscribe, useAction };
}
async function trigger(action: Set<Function>, ...params: any[]) {
return Promise.all(getAllTask(action, ...params));
}
function getAllTask(typeTasks: Set<Function>, ...params: any[]) {
const tasks: Promise<any>[] = [];
typeTasks.forEach((callback) => {
tasks.push(callback(...params));
});
return tasks;
}
function typeofData(data: Set<Function>): DataType;
function typeofData(data: Set<Function>[]): DataType;
function typeofData(data: Record<string, Set<Function>>): DataType;
function typeofData(data: any): DataType {
let type = Object.prototype.toString.call(data);
// 去掉两边的 []
type = type.slice(1, type.length - 1);
// 按空格分割字符串
return type.split(' ')[1] as DataType;
}
function getInitTypeVal(type: DataType) {
const obj: {
Object: Record<string, Set<Function>>;
Array: Set<Function>[];
Set: Set<Function>;
} = {
Object: {},
Array: [],
Set: new Set<Function>()
};
return obj[type];
}
export {create};