这篇文章将介绍在 React 和 TypeScript 利用中,如何勾销fetch申请

一个 React 组件

以下是一个通过 Web API 获取一些数据并进行渲染的 React 组件

export function App() {  const [status, setStatus] = React.useState<    "loading" | "loaded" | "cancelled"  >("loading");  const [data, setData] = React.useState<Character | undefined>(undefined);  React.useEffect(() => {    getCharacter(1).then((character) => {      setData(character);      setStatus("loaded");    });  }, []);  if (status === "loading") {    return (      <div>        <div>loading ...</div>        <button>Cancel</button>      </div>    );  }  if (status === "cancelled") {    return <div>Cancelled</div>;  }  return <div>{data && <h3>{data.name}</h3>}</div>;}

网络数据通过 useEffect 中的getCharacter函数获取,而后再应用useState设置到 data

同时,咱们定义一个status 变量用来存储申请数据时的状态('申请中'/'申请已实现'/'申请已勾销'/).留神,当状态处于'申请中'时,界面会渲染一个 ”勾销“ 按钮

当点击”勾销“ 按钮后,咱们就能够勾销 fetch 申请

接下来,让咱们看看getCharacter函数外面有什么

async function getCharacter(id: number) {  const response = await fetch(`https://swapi.dev/api/people/${id}/`);  const data = await response.json();  assertIsCharacter(data);  return data;}

代码中通过 fetch 调用了一个收费的接口并返回申请到的数据

上面 Character的类型

type Character = {  name: string;};

接下来,再看看assertIsCharacter函数

function assertIsCharacter(data: any): asserts data is Character {  if (!("name" in data)) {    throw new Error("Not character");  }}

通过 TypeScript 的 类型断言 将数据类型设置为Character

应用AbortController来勾销 fetch

1AbortController 是 JavaScript 的最新版本中的个性,它是在 fetch 被实现之后呈现的。 更好的音讯是所有古代浏览器都反对它。

AbortController 蕴含一个 abort 办法。 它还蕴含一个能够传递给fetchsignal属性。 当调用 AbortController.abort 时,fetch申请就会被勾销。

让咱们在 getCharacterfetch申请中应用 AbortController 及其signal属性:

function getCharacter(id: number) {  // 获取AbortController实例  const controller = new AbortController();  // 获取 signal属性  const signal = controller.signal;  const promise = new Promise(async (resolve) => {    const response = await fetch(`https://swapi.dev/api/people/${id}/`, {      method: "get",      // 将 signal作为fetch的参数之一      signal,    });    const data = await response.json();    assertIsCharacter(data);    resolve(data);  });  // 设置一个 勾销函数  promise.cancel = () => controller.abort();  return promise;}

咱们从getCharacter函数中删除了async关键字,并将现有代码包装在一个新的Promise中。 当申请到数据后,咱们应用resolve将数据抛出去。 咱们在Promise中增加了一个cancel办法,该办法调用了AbortController.abort

蕴含 cancel 办法的 PromisegetCharacter 中被返回,以便咱们在业务代码中能够应用它来勾销申请。

保留代码查看界面成果,发现有一个类型谬误:

//  - Property 'cancel' does not exist on type 'Promise<unknown>'promise.cancel = () => controller.abort();

让咱们为Promisecancel 办法创立一个类型

interface PromiseWithCancel<T> extends Promise<T> {  cancel: () => void;}// 应用 然应用类型断言来解决后面的类型谬误function getCharacter(id: number) {  ...  (promise as PromiseWithCancel<Character>).cancel = () => controller.abort();  return promise as PromiseWithCancel<Character>;}

在 React 组件中应用getCharacter

咱们将把getCharacter返回的 promise 存储在一个名为query的状态变量中。

export function App() {  const [status, setStatus] = React.useState<"loading" | "loaded" | "cancelled">("loading");  const [data, setData] = React.useState<Character | undefined>(undefined);  const [query, setQuery] = React.useState<PromiseWithCancel<Character> | undefined>(undefined);  React.useEffect(() => {    const q = getCharacter(1);    setQuery(q);    q.then((character) => {      setData(character);      setStatus("loaded");    });  }, []);  ...

当初,当点击勾销按钮的时候,咱们调用 promise 中的cancle办法

<button  onClick={() => {    query?.cancel();    setStatus("cancelled");  }}>  Cancel</button>

点击勾销按钮后吗,咱们看到发现’Cancelled‘文案被渲染进去了

再通过谷歌开发者工具查看网络申请,发现申请也被勾销了

很棒是吧!

捕捉"勾销申请"产生的谬误

让咱们再看看控制台,当申请被勾销后,有谬误被抛出了

咱们能够应用 try catch 来包裹申请以便捕捉谬误

const promise = new Promise(async (resolve) => {  try {    const response = await fetch(`https://swapi.dev/api/people/${id}/`, {      method: "get",      signal,    });    const data = await response.json();    assertIsCharacter(data);    resolve(data);  } catch (ex: unknown) {    if (isAbortError(ex)) {      console.log(ex.message);    }  }});

isAbortError类型的函数如下

function isAbortError(error: any): error is DOMException {  if (error && error.name === "AbortError") {    return true;  }  return false;}

当初当咱们再次点击勾销按钮,咱们会在控制台收到一条音讯提醒而不是一个谬误

总结

能够将AbortController中的signal属性传递给fetch。 而后能够调用AbortController.abort勾销申请。

勾销 fetch 会引发一个谬误,但能够应用try catch将其捕捉。

参考文档: https://www.carlrippon.com/ca...