You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React封装自定义Hook实现基于AbortController的请求自动取消

解决React中自动取消API请求的自定义Hook方案

核心思路

为每个需要自动取消的API请求创建独立的AbortController实例,绑定组件生命周期:组件卸载时自动终止请求,依赖变化时主动取消旧请求并生成新控制器,无需手动重复创建控制器。

第一步:封装useAutoAbort自定义Hook

这个Hook会自动管理AbortController的生命周期,提供可重置的信号源:

import { useState, useEffect, useCallback } from 'react';

export function useAutoAbort() {
  // 用useState保存控制器,确保重置时触发依赖更新
  const [controller, setController] = useState(() => new AbortController());

  // 组件卸载时自动终止请求
  useEffect(() => {
    const currentController = controller;
    return () => currentController.abort();
  }, [controller]);

  // 重置控制器:取消当前请求并生成新实例
  const resetRequest = useCallback(() => {
    controller.abort();
    setController(new AbortController());
  }, [controller]);

  return {
    signal: controller.signal,
    resetRequest
  };
}

第二步:在FormProvider中配合useApiData使用

每个API请求对应一个独立的useAutoAbort实例,避免请求间互相干扰:

import { useAutoAbort } from './hooks/useAutoAbort';

function FormProvider({ children }) {
  // 为用户数据请求创建自动取消控制器
  const { signal: userSignal, resetRequest: resetUserReq } = useAutoAbort();
  const { data: userData, loading: isUserLoading, error: userError } = useApiData(
    '/api/user',
    { signal: userSignal }
  );

  // 为配置数据请求创建自动取消控制器
  const { signal: configSignal, resetRequest: resetConfigReq } = useAutoAbort();
  const { data: configData, loading: isConfigLoading, error: configError } = useApiData(
    '/api/config',
    { signal: configSignal }
  );

  // 当依赖变化时,重置请求(取消旧请求,触发新请求)
  useEffect(() => {
    resetUserReq();
  }, [someUserDependency, resetUserReq]);

  useEffect(() => {
    resetConfigReq();
  }, [someConfigDependency, resetConfigReq]);

  const contextValue = {
    userData,
    isUserLoading,
    userError,
    configData,
    isConfigLoading,
    configError
  };

  return (
    <FormContext.Provider value={contextValue}>
      {children}
    </FormContext.Provider>
  );
}

第三步:确保useApiData正确处理AbortError

在你的useApiData Hook中,忽略预期的取消错误,避免更新无效状态:

import { useState, useEffect } from 'react';

export function useApiData(url, options = {}) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      setError(null);
      try {
        const response = await fetch(url, { ...options });
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        setData(await response.json());
      } catch (err) {
        // 跳过AbortError,因为这是主动取消的预期行为
        if (err.name !== 'AbortError') setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url, options]);

  return { data, loading, error };
}

为什么之前的useAbortController没生效?

大概率是这两个原因:

  1. 多个请求共用同一个AbortController,导致一个请求取消会影响其他请求
  2. 控制器重置时没有触发状态更新,导致useApiData的依赖未变化,无法重新发起请求

内容的提问来源于stack exchange,提问作者Ludwig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:59:20