【问题标题】:How to integrate AbortController with Axios and React?如何将 AbortController 与 Axios 和 React 集成?
【发布时间】:2022-09-23 21:31:57
【问题描述】:

Abortcontroller 信号不适用于我在 React 中的 Axios。

我想用 AbortController 替换 CancelToken(因为它已被弃用),但它不起作用,相应的请求没有被取消。

  let testController: AbortController;

  function loadTest() {
    testController = new AbortController();

    TestAPI.getTest(testController.signal)
      .then((e) => {
        console.log(e.data);
      })
      .catch((e) => {
        console.error(e);
      });
  }

同样在 UseEffect Cleanup 我这样做(这里应该取消)并且信号的状态设置为中止,但仍然没有取消请求:

  useEffect(() => () => {
    if (testController) testController.abort();
    // console.log(testController.signal.aborted) => **true**
  }, []);

这是我的 API,我将 AbortSignal 传递给请求:

  getTest(signal?: AbortSignal): Promise<AxiosResponse<Test[]>> {
    return axios.get(`${URI}/test`, { signal });
  },

使用 Axios.CancelToken.source 时工作正常,但现在使用 AbortController,请求永远不会被取消。

使用:\"axios\":\"^0.26.0\",

有人设法将 AbortController 与 React 和 Axios 集成了吗?还是 AbortController只要使用获取?

    标签: reactjs react-native axios cancellation cancellationtokensource


    【解决方案1】:

    据我所知,axios.CancelToken API 并未被弃用,它仍在规范中,但根据文档,axios 还支持fetch APIAbortController

    Cancellation

    Axios 支持 AbortController 以 fetch API 的方式中止请求:

    const controller = new AbortController();
    
    axios.get('/foo/bar', {
       signal: controller.signal
    }).then(function(response) {
       //...
    });
    // cancel the request
    controller.abort()
    

    目前尚不清楚 testController 的确切声明位置:

    let testController: AbortController;
    

    但我怀疑它在函数组件的主体中,并在随后的渲染周期中重新声明。

    我建议使用 React ref 来存储 AbortController,并在您的应用程序周围引用此 ref 值。这样组件就可以在渲染周期到渲染周期之间保持控制器的稳定引用,以便在任何 useEffect 挂钩清理函数中引用,以在组件卸载时取消正在进行的请求。

    const abortControllerRef: AbortController = useRef<AbortController>(
      new AbortController()
    );
    
    function loadTest() {
      TestAPI.getTest(abortControllerRef.current.signal)
        .then((e) => {
          console.log(e.data);
        })
        .catch((e) => {
          console.error(e);
        });
    }
    
    useEffect(() => {
      const controller = abortControllerRef.current;
      return () => {
        controller.abort();
      };
    }, []);
    

    【讨论】:

    • 你为什么建议参考?
    • @Silidrone 是在 React 函数组件作用域中声明的作为参考所以它是从渲染周期到渲染周期的稳定参考因此可以在组件卸载时在useEffect 清理函数中引用它。
    • 如果它不是 ref,那么在 useEffect 清理函数中引用它会是未定义/危险的行为吗?
    • @Silidrone 我仍然相信 OP 的问题是在每个渲染周期声明/重新声明中止控制器,因此问题更有可能是当前声明的中止控制器不是传递给 Axios 请求的那个,所以在它上面调用abort 不会取消正在进行的请求。这正是 OP 描述的行为,他们的请求没有被取消。
    • @Silidrone 抱歉,我想我对 Javascript 闭包以及 React 组件生命周期和钩子有一定的基本知识水平。谢谢你问“为什么”。
    【解决方案2】:

    我建议阅读this post

    简而言之,您想使用useEffect 创建控制器,更重要的是,使用return 语句中止控制器。

    useEffect(() => {
     const controller = new AbortController();
     const signal = controller.signal;
     getData(signal)
    
     //cleanup function
     return () => {controller.abort();};
    }, [fetchClick]);
    

    然后getData 函数可以是您的axious 调用,格式如下:

    const getData = async (signal) =>{
     const res = await axios.get(url, {signal: signal}).then(...)
    }
    

    【讨论】:

      【解决方案3】:

      我想知道的是,如果我的应用程序中有一堆电话怎么办。假设我想在我的应用离线(没有互联网)时取消所有通话。我在哪里设置信号配置。我将它设置在一个拦截器文件中。然后我创建了一个函数 abortCalls()。然后我将把这个函数调用成一个useEFfect。如果不在拦截器中,我应该在哪个 axios 文件中设置此信号配置?

      import axios from 'axios';
      import store from '../store';
      
      const controller = new AbortController();
      
      export const abortCalls = () => {
          controller.abort();
      };
      
      axios.interceptors.request.use(
          (config) => {
              const { UserLogin } = store.getState();
      
              if (UserLogin?.userInfo?.token) {
                  config.headers['Authorization'] = 'Bearer ' + UserLogin.userInfo.token;
              }
      
              config.headers['Content-Type'] = 'application/json';
      
              config.signal = controller.signal;
      
              return config;
          },
      
          (error) => {
              Promise.reject(error);
          }
      );
      
      
      
      

      【讨论】:

        【解决方案4】:

        关于 AbortController 与 axios here 所需的一切

        const controller = new AbortController();
        
        axios.get('/foo/bar', {
           signal: controller.signal
        }).then(function(response) {
           //...
        });
        // cancel the request
        controller.abort()

        【讨论】:

        • 这并没有真正回答如何将其集成到 React 的问题
        猜你喜欢
        • 2019-06-08
        • 2020-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-16
        • 2020-08-09
        • 2019-06-29
        相关资源
        最近更新 更多