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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
| /* eslint-disable @typescript-eslint/no-parameter-properties */
import type { MutableRefObject } from "react";
import type {
FetchState,
Options,
PluginReturn,
Service,
Subscribe,
} from "./types";
import { isFunction } from "../../../../utils";
/**
* 插件化机制
* 只负责完成整体流程的功能,额外的功能都交给插件去实现
* 符合职责单一原则:一个 Plugin 只负责一件事,相互之间不相关,可维护性高、可测试性强
* 符合深模块的软件设计理念。https://www.cnblogs.com/hhelibeb/p/10708951.html
* */
export default class Fetch<TData, TParams extends any[]> {
// 插件执行后返回的方法列表
pluginImpls: PluginReturn<TData, TParams>[];
// 计数器(锁)
count: number = 0;
// 状态值 - 几个重要的数据
state: FetchState<TData, TParams> = {
loading: false,
params: undefined,
data: undefined,
error: undefined,
};
constructor(
// 请求示例 ref
public serviceRef: MutableRefObject<Service<TData, TParams>>,
public options: Options<TData, TParams>,
// 订阅-更新函数
public subscribe: Subscribe,
// 初始状态值
public initState: Partial<FetchState<TData, TParams>> = {}
) {
this.state = {
...this.state,
loading: !options.manual, // 非手动,loading 设为 true
...initState,
};
}
// 更新状态函数
setState(s: Partial<FetchState<TData, TParams>> = {}) {
this.state = {
...this.state,
...s,
};
// 更新,通知 useRequestImplement 组件重新渲染,获取到最新状态值
this.subscribe();
}
// 执行特定阶段的插件方法,包含了一个请求从开始到结束的生命周期(:Mutate 除外
runPluginHandler(event: keyof PluginReturn<TData, TParams>, ...rest: any[]) {
// @ts-ignore
const r = this.pluginImpls.map((i) => i[event]?.(...rest)).filter(Boolean);
// 返回值
return Object.assign({}, ...r);
}
// 执行请求的核心方法!!!
// 如果设置了 options.manual = true,则 useRequest 不会默认执行,需要通过 run 或者 runAsync 来触发执行。
// runAsync 是一个返回 Promise 的异步函数,如果使用 runAsync 来调用,则意味着你需要自己捕获异常。
async runAsync(...params: TParams): Promise<TData> {
// 计数器(锁),cancel 请求需要
this.count += 1;
const currentCount = this.count;
// 请求前
const {
stopNow = false,
returnNow = false,
...state
} = this.runPluginHandler("onBefore", params);
// stop request
if (stopNow) {
return new Promise(() => {});
}
this.setState({
// loading
loading: true,
params,
...state,
});
// return now
// 立即返回,与缓存策略有关
if (returnNow) {
return Promise.resolve(state.data);
}
// options 的 onBefore 回调
this.options.onBefore?.(params);
// 执行请求
try {
// replace service
// 与缓存策略有关,如果有 cache 的 service 实例,则直接使用缓存的实例
let { servicePromise } = this.runPluginHandler(
"onRequest",
this.serviceRef.current,
params
);
if (!servicePromise) {
servicePromise = this.serviceRef.current(...params);
}
const res = await servicePromise;
if (currentCount !== this.count) {
// prevent run.then when request is canceled
return new Promise(() => {});
}
// const formattedResult = this.options.formatResultRef.current ? this.options.formatResultRef.current(res) : res;
// 更新状态
this.setState({
data: res,
error: undefined,
loading: false,
});
// options 的 onSuccess 回调
this.options.onSuccess?.(res, params);
// plugin 的 Onsuccess 事件
this.runPluginHandler("onSuccess", res, params);
// options 的 onFinally 回调
this.options.onFinally?.(params, res, undefined);
if (currentCount === this.count) {
// plugin 的 onFinally 事件
this.runPluginHandler("onFinally", params, res, undefined);
}
return res;
// 异常捕获
} catch (error) {
if (currentCount !== this.count) {
// prevent run.then when request is canceled
return new Promise(() => {});
}
// 更新状态
this.setState({
error,
loading: false,
});
// options 的 onError 回调
this.options.onError?.(error, params);
// plugin 的 onError 事件
this.runPluginHandler("onError", error, params);
// options 的 onFinally 回调
this.options.onFinally?.(params, undefined, error);
// plugin 的 onFinally 事件
if (currentCount === this.count) {
this.runPluginHandler("onFinally", params, undefined, error);
}
// 抛出异常
throw error;
}
}
// run 同步函数,其内部调用了 runAsync 方法
run(...params: TParams) {
this.runAsync(...params).catch((error) => {
if (!this.options.onError) {
console.error(error);
}
});
}
// 取消当前正在进行的请求
cancel() {
// 设置 this.count + 1,在 runAsync 的执行过程中,通过判断 currentCount !== this.count,达到取消请求的目的
this.count += 1;
this.setState({
loading: false,
});
// 执行 plugin 的 onCancel
this.runPluginHandler("onCancel");
}
// 使用上一次的 params,重新调用 run
refresh() {
// @ts-ignore
this.run(...(this.state.params || []));
}
// 使用上一次的 params,重新调用 runAsync
refreshAsync() {
// @ts-ignore
return this.runAsync(...(this.state.params || []));
}
// 修改 data
mutate(data?: TData | ((oldData?: TData) => TData | undefined)) {
const targetData = isFunction(data) ? data(this.state.data) : data;
this.runPluginHandler("onMutate", targetData);
this.setState({
data: targetData,
});
}
}
|