react-query手把手教程⑨-取消查询

677 阅读3分钟

该系列其他文章可以点击查看专栏:react-query手把手教程

介绍

如果组件中的查询在卸载前未完成数据加载,那么react-query将会自动取消该请求。或者某个查询键在获取数据的过程中有更改,此时数据请求也会被取消(因为更改查询键后,之前的数据实际上来说已经没有用处了)。

所以在大多数情况下,你不需要手动去取消请求。

取消请求可以节省用户和服务器的网络资源。如果请求在发送之前被取消的话,服务器就无需进行响应;即使服务器响应了请求并返回了结果,客户端其实也不需要花费资源去处理后端数据。因此取消查询对于提升用户体验及性能非常有帮助。

实践

AbortController事件监听

react-query使用AbortControllerAPI来控制取消,库已经封装好相关调用,你只需接收相关取消信号即可。

有兴趣的同学,可以阅读这些扩展资料:

点击查看API兼容性MDN文档

获取取消信号的操作,通常在一些需要获取数据后执行异步操作的流程中非常实用。现在举个例子:假如需要在请求结束后,通过setTimeout执行后续的一些操作,如果该请求被取消,那么就取消应该setTimeout操作,伪代码如下:

const DelayComponent = () => {
  const delayQuery = useQuery(
    ["delay"], 
    // ①
    ({signal}) => {
      let timeout;
      const delayPromise = new Promise(resolve => {
        timeout = setTimeout(() => resolve("Hello"), 1000);
      })


      // ②
      signal?.addEventListener("abort", () => {
        clearTimeout(timeout);
      });


      return delayPromise; 
    })

  // ...
}

①:可以看到上面的例子传入的执行查询的方法中,解构出了react-query的signal,它是AbortSignal实例化后的结果。

你可以在②中直接监听其abort事件来知道,当前请求已被取消,需要将相关后续异步操作一并清除掉。

用户手动取消请求

fetchAbortController

将实例化后的AbortController传入fetch时,一旦手动触发取消请求,fetch将会立即取消本次的请求,无需做其它的设置。例子如下:

const userQuery = useQuery(
  ["users"], 
  ({signal}) => fetch("/api/users", {signal})
    .then(res => res.json())
);

手动调用取消

可以为用户提供手动取消请求的按钮,只需要调用queryClient中的cancelQueries方法来取消当前正在请求的查询。请注意,调用时需要传入查询键过滤器(因此其实可以批量取消)。比如下面这个例子:

import { useQueryClient, useQuery } from 'react-query'

const Users = () => {
  const queryClient = useQueryClient();

  const userQuery = useQuery(
    ["users"], 
    // ②
    ({signal}) => fetch("/api/users", {signal})
      .then(res => res.json())
  );

  return (
    <div>
      // ①
      <button onClick={() => queryClient.cancelQueries(["users"])}>
        取消请求
      </button>
      <div>
        {/* ... */}
      </div>
    </div>
  )
}

当用户取消请求时,["users"]查询将会被自动终止。

可以看到在这里将实例化后的AbortControllersignal解构出来后,传入了fetch的参数中,当fetch接收到了用户主动取消的信号时,将会自动取消当前的请求。

这里需要注意以下几个点:

  • 如果手动取消已有缓存的查询,react-query将会继续返回缓存中之前存储的过期信息
  • 如果接口是在第一次请求时被取消,那么该查询如果没有满足任何重新获取的条件下,将会永远不会被调用,并且当前的状态为idle,直到查询重新被获取

总结

  • react-query底层依赖AbortController来实现取消请求的能力
  • 可以监听实例化后AbortControllerabort事件来监听当前请求是否被取消
  • fetch可以将传入实例化后的AbortController作为singal参数传入,一旦用户触发取消时间,请求将会被取消
  • queryClient.cancelQueries传入查询过滤器可批量取消请求

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 16 天,点击查看活动详情