useAbortableRequest
# web API 之 AbortController
AbortController: abort()方法 (opens new window)
AbortController 接口的 abort() 方法会在一个异步操作完成之前中止它。它能够中止 fetch 请求、各种响应主体或者流的消耗。
const controller = new AbortController();
const signal = controller.signal;
const url = "video.mp4";
const downloadBtn = document.querySelector(".download");
const abortBtn = document.querySelector(".abort");
downloadBtn.addEventListener("click", fetchVideo);
abortBtn.addEventListener("click", () => {
controller.abort();
console.log("Download aborted");
});
function fetchVideo() {
fetch(url, { signal })
.then((response) => {
console.log("Download complete", response);
})
.catch((err) => {
console.error(`Download error: ${err.message}`);
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 工作需求
在工作中,ant design
表格会在查询后发起请求,有时候用户请求较快,会造成过多的重复请求,会对服务器造成较大的压力,于是就有了希望能在上一次请求没有完成,但是已经发起下一次请求的同时,能够取消上一次的请求。
# 代码实现
import { useState, useCallback } from 'react';
/**
* 使用umi.js和AbortController实现的防止重复请求的React Hook
* @param {Function} requestFunction - 请求函数,该函数需要返回一个Promise
* @returns {Array} - 返回一个数组,包含请求函数和当前请求状态
*/
function useAbortableRequest(requestFunction) {
// 保存当前的AbortController实例
const [controller, setController] = useState(null);
// 请求状态
const [loading, setLoading] = useState(false);
const sendRequest = useCallback(async (...args) => {
// 如果存在上一个请求,先取消上一个请求
if (controller) {
controller.abort();
}
// 创建新的AbortController实例
const newController = new AbortController();
setController(newController);
setLoading(true);
try {
// 调用请求函数,传入signal
const response = await requestFunction(...args, { signal: newController.signal });
setLoading(false);
return response;
} catch (error) {
// 如果请求被取消,不更新loading状态
if (error.name !== 'AbortError') {
setLoading(false);
}
throw error;
}
}, [controller, requestFunction]);
return [sendRequest, loading];
}
export default useAbortableRequest;
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
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
使用示例:
import React, { useEffect } from 'react';
import { useAbortableRequest } from './useAbortableRequest';
import { request } from 'umi';
// 模拟请求函数
const fetchData = (params, { signal }) => {
return request('/api/data', { method: 'GET', params, signal });
};
const MyComponent = () => {
const [fetchDataWithAbort, loading] = useAbortableRequest(fetchData);
useEffect(() => {
fetchDataWithAbort({ query: 'example' })
.then(response => {
console.log(response);
})
.catch(error => {
if (error.name !== 'AbortError') {
console.error(error);
}
});
// 组件卸载时取消请求
return () => {
fetchDataWithAbort();
};
}, [fetchDataWithAbort]);
return <div>{loading ? '加载中...' : '加载完成'}</div>;
};
export default MyComponent;
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
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
这个Hook useAbortableRequest
接收一个请求函数作为参数,返回一个可以被调用的请求函数和当前请求的加载状态。请求函数内部使用AbortController
来取消上一个未完成的请求,以防止重复请求。
最近更新~: 2024/08/19, 01:05:55