-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC]是否考虑在useRequest中引入AbortController #2593
Comments
看了一下,有很多类似执行取消或者监听取消的诉求
|
如果要解决这个问题,是不是直接在 onBefore 里支持取消 promise 的执行就好了,比如 onBefore 里如果返回的是 false,onRequest 就不执行了。 |
onBefore是service还没有开始执行的时候吧,我的场景是service已经开始执行,但还没结束(fetch请求已发出没收到响应) |
合理,整,不过我看 fetch 的 signal,兼容性没那么好,到时候可能需要注意一下。 |
这个还好,那也是请求库的事,用户可以自己实现取消,https://tanstack.com/query/v4/docs/framework/react/guides/query-cancellation |
另外如果要中断的话,自己封装下 useRequest 也可以
|
稍加包装一下就行 function useRequestWithAbort(service, { manual }) {
const [responseData, setResponse] = useState({});
const abortControllerRef = useRef(null);
const { loading, run, cancel } = useRequest(service, {
manual: manual, // 是否手动触发
onSuccess: (response) => {
setResponse(response);
},
onError: (error) => {
console.log(error);
// notification.error({
// message: "请求错误",
// description: error.message,
// });
},
});
const handleRequest = async (params = {}) => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
abortControllerRef.current = new AbortController();
return run({ signal: abortControllerRef.current.signal, ...params });
};
const handleCancel = () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
cancel();
// console.log("请求取消");
};
return { handleRequest, handleCancel, loading, responseData };
}
export default useRequestWithAbort; |
import { useRef } from 'react';
import { useRequest } from 'ahooks';
type IService<TData, TParams extends any[]> = (signal: AbortSignal, ...args: TParams) => Promise<TData>;
type IOptions<TData, TParams extends any[]> = Parameters<typeof useRequest<TData, TParams>>[1];
type IPlugins<TData, TParams extends any[]> = Parameters<typeof useRequest<TData, TParams>>[2];
/**
* 对ahooks的useRequest做二次封装,自动未每一次请求生成AbortController
*/
const useRequestWithAbortController = <TData, TParams extends any[]>(
service: IService<TData, TParams>,
options?: IOptions<TData, TParams>,
plugins?: IPlugins<TData, TParams>,
) => {
const abortControllerRef = useRef<AbortController>();
const ret = useRequest<TData, TParams>(
(...params) => {
if (abortControllerRef.current) {
abortControllerRef.current.abort('竞态终止');
}
const controller = new AbortController();
abortControllerRef.current = controller;
return service.call(this, controller.signal, ...params);
},
{
...options,
onFinally: (...args) => {
abortControllerRef.current = undefined;
options?.onFinally?.(...args);
},
},
plugins,
);
return { ...ret, abortController: abortControllerRef.current };
};
export default useRequestWithAbortController; |
目前useRequest的做法,是通过标记在竞态问题出现时,标记忽略之前请求回调(onSuccess)执行。
新加的cancel方法可以主动标记,让service执行结束后的回调(onSuccess)不再执行。
但是,这些对于并不能终止service内部的执行。
使用AbortController可以实现fetch的提前中止
自己实现过于繁琐,看看能否直接在useReuqest的时候,默认生成一个controller,传递给service方法,并且在合适时机自动调用abort方法(竞态时、cancel时)。
虽然说覆水难受,已发出去的请求服务器仍然会收到,但仍然一定以上能过做到性能提升
#862
#2039
#1715 (comment) 目前AbortController应该不再属于实验性质了
The text was updated successfully, but these errors were encountered: