中止获取
AbortController 提供了一种新方式,用于取消不再相关的请求。它可以通过第二个 RequestInit 参数接入 fetch。
Resource
RestEndpoint 通过 signal 成员提供了简单的集成方式:
const abort = new AbortController();
const AbortableArticle = CoolerArticleResource.get.extend({
signal: abort.signal,
});
// ...somewhere later trigger cancellation
abort.abort();
Endpoint
此外,借助自定义成员,也可以轻松地为任何 endpoint 添加类似的功能。
type Params = { id: string };
const UserDetail = new Endpoint(
function ({ id }: Params) {
const init: RequestInit = {};
if (this.signal) {
init.signal = this.signal;
}
return fetch(this.url({ id }), init).then(res => res.json()) as Promise<
typeof payload
>;
},
{
url({ id }: Params) { return `/users/${id}` },
signal: undefined as AbortSignal | undefined,
},
);
const abort = new AbortController();
const AbortableUserDetail = UserDetail.extend({
signal: abort.signal,
});
// ...somewhere later trigger cancellation
abort.abort();
参数变化时取消
有时用户需要填写一个字段,而该字段会影响网络请求的结果。如果这是一个文本输入框,用户可能输入得很快,从而产生大量网络请求。
使用 useCancelling() 会在请求完成之前、参数发生变化时,自动取消正在进行中的请求。
resources/Todo
TodoDetail
Demo
import { useSuspense, useCancelling } from '@data-client/react'; import { TodoResource } from './resources/Todo'; export default function TodoDetail({ id }: { id: number }) { const todo = useSuspense(useCancelling(TodoResource.get, { id }), { id, }); return <div>{todo.title}</div>; }
结果
Store▶
试着快速点击 »。如果你在请求完成之前递增,请求将被取消,你在 store 中也不会看到结果。
警告
当许多互不相关的组件向 useSuspense() 传入相同的参数(Endpoint/params 组合)进行获取时,使用它要格外小心。该方案按组件中止请求,这意味着你可能会取消另一个组件仍然需要的请求。