译零 TransZero · TanStack Query v4 中文文档
主站

查询取消 Query Cancellation

React Query 为每个查询函数都提供了一个AbortSignal的实例,当且仅当你的运行环境支持该对象。 当一个查询变得过时或者不活跃,那么该“信号”将被中止。 这意味着,所有的查询都是可取消的,而且如果需要,你可以在查询函数中响应取消动作。 这最为方便的一点是,你可以继续使用普通的 async/await 语法,同时获得自动取消的所有好处。 此外,这个解决方案比旧的解决方案更适合 TypeScript。

AbortController API 在大多数运行时环境中都是可用的。但是如果你的运行时环境不支持它,那么查询函数将在对应的地方接收到 undefined。 当然,你可以选择手动实现 AbortController API,在 npm 上有几个可用的。

默认行为

正常情况下,未挂载的或在其返回的 Promise 被 resolve/reject 之前的查询是不会被自动取消的。 顺利的话,在 resolve 之后的数据将在缓存中可用,reject 后的 error 可用。 不顺利的话,如果在已经开始接收一个查询且在其结束之前卸载组件,不会产生任何不利影响。并且若再次挂载此组件,且查询还被自动垃圾回收,那么数据可用。

但是,如果你使用了 AbortSignal 或者是给 Promise 附加了一个 cancel 函数,那么这个 Promise 是可以被取消的(例如,下面的使用 fetch 示例)。 此时查询也必须被取消。 取消查询将会导致其恢复到以前的状态。

使用 fetch

TypeScript
1const query = useQuery({2  queryKey: ['todos'],3  queryFn: async ({ signal }) => {4    const todosResponse = await fetch('/todos', {5      // 传递可撤销的信号到fetch里去6      signal,7    })8    const todos = await todosResponse.json()9 10    const todoDetails = todos.map(async ({ details } => {11      const response = await fetch(details, {12        // 或这将他传递给好几个实例13        signal,14      })15      return response.json()16    })17 18    return Promise.all(todoDetails)19  }20})

使用 axios

使用 axios ^0.22.0

TypeScript
1import axios from "axios";2 3const query = useQuery({4  queryKey: ["todos"],5  queryFn: ({ signal }) =>6    axios.get("/todos", {7      // 传递可撤销的信号到 `axios`8      signal,9    }),10});

使用 axios (版本低于 0.22.0)

TypeScript
1import axios from "axios";2 3const query = useQuery({4  queryKey: ["todos"],5  queryFn: ({ signal }) => {6    // 给这个 request 创建一个 CancelToken7    const CancelToken = axios.CancelToken;8    const source = CancelToken.source();9 10    const promise = axios.get("/todos", {11      // 传递这个 token 到该请求12      cancelToken: source.token,13    });14 15    // 如果 React Query 信号是 abort,那么撤销该请求16    signal?.addEventListener("abort", () => {17      source.cancel("Query was cancelled by React Query");18    });19 20    return promise;21  },22});

使用 XMLHttpRequest

TypeScript
1const query = useQuery({2  queryKey: ["todos"],3  queryFn: ({ signal }) => {4    return new Promise((resolve, reject) => {5      var oReq = new XMLHttpRequest();6      oReq.addEventListener("load", () => {7        resolve(JSON.parse(oReq.responseText));8      });9      signal?.addEventListener("abort", () => {10        oReq.abort();11        reject();12      });13      oReq.open("GET", "/todos");14      oReq.send();15    });16  },17});

使用 graphql-request

使用 graphql-request ^4.0.0

可以传递一个 AbortSignal 给客户端的 request 函数。

TypeScript
1const client = new GraphQLClient(endpoint);2 3const query = useQuery({4  queryKey: ["todos"],5  queryFn: ({ signal }) => {6    client.request({ document: query, signal });7  },8});

使用 graphql-request (版本低于 4.0.0)

可以传递一个 AbortSignal 给 GraphQLClient 的构造函数.

TypeScript
1const query = useQuery({2  queryKey: ["todos"],3  queryFn: ({ signal }) => {4    const client = new GraphQLClient(endpoint, {5      signal,6    });7    return client.request(query, variables);8  },9});

手动取消

有时,你可能会想手动取消。 例如:请求需要很长时间才能完成,因此用户可以单击“取消”按钮来停止请求。 为此,你只需要调用 queryClient.cancelQueries(key),取消此次查询并将数据还原到上一次的状态。 如果 promise.cancel 可用或者你在查询函数内已经处理了 signal,React Query 就会取消该 Promise 同时取消对应请求。

TypeScript
1const query = useQuery({2  queryKey: ["todos"],3  queryFn: async ({ signal }) => {4    const resp = await fetch("/todos", { signal });5    return resp.json();6  },7});8 9const queryClient = useQueryClient();10 11return (12  <button13    onClick={(e) => {14      e.preventDefault();15      queryClient.cancelQueries(["todos"]);16    }}17  >18    Cancel19  </button>20);

本页为 TanStack Query 文档(React 版)的非官方中文翻译,原文由上游团队维护,遵循 MIT 许可。 译文如有偏差,以英文原文为准。

本页译文取自社区中文版 react-query-web-i18n(MIT),非本站翻译,已停止更新,内容可能与当前 API 有出入。

译自上游 (未记录版本)