javascript - 使用 useInterval 钩子(Hook)取消异步请求

标签 javascript reactjs react-hooks

使用 useEffect 的清理功能可以非常轻松地取消请求

useEffect(() => {
  let ignore = false;
  fetchData(id).then(data => {
    if (!ignore) {
      setData(data);
    }
  });
  return () => (ignore = true);
}, [id]);

我想做类似的事情,但我需要使用 useInterval 轮询数据

我想使用 fetchData(id) 轮询数据,如果请求已触发但 id 在响应解析之前发生了更改,则忽略返回的响应。

最佳答案

针对您的具体情况进行破解

假设您收到 id 作为 props 或类似的东西,这会起作用吗?

const Foo = ({ id }) => {
  const [data, setData] = useState()

  const passedId = useRef()
  passedId.current = id

  useInterval(() => {
    fetchData(id)
      .then(response => id === passedId.current && setData(response))
  }, 5000)

  // Render some JSX with the data

我在本地测试了与此非常相似的东西,基本上发生的事情是这样的:

  1. Foo 接收 id = 6
  2. 6 存储在 passedId
  3. useInterval 滴答声,我们请求 id = 6
  4. 组件接收id = 7
  5. 7 存储在 passedId
  6. id = 6 的请求已完成,但 passedId.current === 7 因此未调用 setData
  7. id = 7 请求完成,id === PassedId.current 并调用 setData

将类似的内容放入useInterval

注意 - 未经测试

也许取消效果如此简单的原因是因为该函数返回自己的清理,因此 ignore 不必在外部范围内。但 setInterval 不允许返回值。我们也许可以使用setTimeout来解决这个问题:

function useInterval(callback, delay) {
  useEffect(() => {
    let cleanup
    let id
    function tick() {
      cleanup = callback()
      id = setTimeout(tick, delay)
    }
    if (delay !== null) {
      tick()
      return () => {
        clearTimeout(id)
        cleanup && cleanup()
      }
    }
    return () => cleanup && cleanup()
  }, [callback, delay])

其中的一个问题是,现在我们在依赖项数组中有 callback,因此应该使用 useCallback 创建给 useInterval 的回调:

const Foo = ({ id }) => {
  const [data, setData] = useState()

  const pollData = useCallback(() => {
    let shouldUpdate = true

    fetchData(id).then(resp => shouldUpdate && setData(resp))

    return () => shouldUpdate = false
  }, [id])

  useInterval(pollData, 5000)

  // Render some JSX with the data
  1. 当调用 useInterval 时,我们设置一个 useEffect 来执行callback
  2. callback执行时,返回值(它的清理)被存储在cleanup中,它的作用域是effect和一个setTimeout设置为在延迟毫秒
  3. 后重新执行
  4. 如果 callback 发生变化(即我们获得新的 id),那么我们会清除超时并为之前的回调运行清理
  5. delay毫秒后,再次执行tick

关于javascript - 使用 useInterval 钩子(Hook)取消异步请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58258713/

相关文章:

javascript - 具有嵌套函数的函数是否被视为单个函数?

javascript - XSS - 哪些浏览器会自动转义地址栏中的网址?

javascript - iOS 上的 Mobile Safari 在大页面上崩溃

javascript - 将 ID(Index) 传递给 onEditDetail() 参数

javascript - 我在将 Prop 从状态传递给 child 时遇到问题

javascript - 推送到 React 状态数组

javascript - 当你使用 set 函数时,React 会克隆你的对象吗?

javascript - 使用 Typescript 将 prop 渲染为字符串或组件

javascript - 在渲染 react Hook 之前等待 API 数据

reactjs - 如何将每次点击的 react 钩子(Hook)状态传递给另一个组件