【问题标题】:Cancel async request on unmount with axios使用 axios 取消卸载时的异步请求
【发布时间】:2018-02-17 00:03:46
【问题描述】:

我有多个带有axios 插件的组件用于一些获取请求。我需要一些帮助来取消所有在 react js 中的组件卸载事件中使用 axios 的 xhr 请求。但是 axios 取消代码不起作用。它的 return me cancel() 不是函数错误。

代码示例:-

import axios from 'axios';


var CancelToken = axios.CancelToken;
var cancel;

axios.get('abc/xyz', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();

请帮我在 axios 中实现取消请求。

谢谢。

【问题讨论】:

    标签: reactjs axios


    【解决方案1】:

    除非您使用RxJS,否则您无法取消请求。我建议你为此目的使用 redux-observable。检查this 了解更多信息。您必须在 Epic 中使用 takeUntil 运算符,并在取消操作触发时执行取消操作。这是上述资源给出的示例代码。

    import { ajax } from 'rxjs/observable/dom/ajax';
    
    const fetchUserEpic = action$ =>
      action$.ofType(FETCH_USER)
        .mergeMap(action =>
          ajax.getJSON(`/api/users/${action.payload}`)
            .map(response => fetchUserFulfilled(response))
            .takeUntil(action$.ofType(FETCH_USER_CANCELLED))
        );
    

    【讨论】:

    • 这段代码(redux-observable)是在工作还是与承诺和组件结构有关?
    • 它使用 RxJS Observables,这是从您的响应创建的事件流。然后您必须创建对 Observable 的订阅才能获得结果。它还提供了很好的组合 api,其中包含许多运算符,例如 map、flatmap、zip 等。它是一种不同于 ES6 fetch 和基于 promise 的方法的范例。这种更可组合的方法。
    • 你能在不使用 redux 或服务器的情况下给我一些想法吗?实际上,我创建了一个非常小的级别应用程序,它有 2 或 3 个随路线变化的组件。我必须在反应 js 生命周期中取消我对 unmount() 的所有 api 请求。
    【解决方案2】:

    使用faxios 代替 axios

     let req = faxios()
      .url('abc/xyz')
    
      .GET
    
      .then(res => {})
      .catch(err => {});
    
    // canceling...
    req.cancel();
    

    【讨论】:

      【解决方案3】:

      这很简单。在componentDidMount 中创建请求并在componentWillUnmount 中取消它。将 url 替换为现有的 JSON 文件,此 sn-p 将按预期工作:

      class MyComponent extends Component {
        constructor (props) {
          super(props)
      
          this.state = {
            data: []
          }
        }
      
        componentDidMount () {
          this.axiosCancelSource = axios.CancelToken.source()
      
          axios
            .get('data.json', { cancelToken: this.axiosCancelSource.token })
            .then(response => {
              this.setState({
                data: response.data.posts
              })
            })
            .catch(err => console.log(err))
        }
      
        componentWillUnmount () {
          this.axiosCancelSource.cancel('Axios request canceled.')
        }
      
        render () {
          const { data } = this.state
      
          return (
           <div>
                {data.items.map((item, i) => {
                  return <div>{item.name}</div>
                })}
            </div>
          )
        }
      }

      【讨论】:

        【解决方案4】:

        除了@taeenb 响应,如果您使用反应钩子,这里有一个示例。

        使用 useHook检测路线变化。然后,在路由卸载时取消带有 TOKEN 的请求,并生成一个新的 TOKEN 来发出新的请求。有关详细信息,请参阅 Axios 文档 (https://github.com/axios/axios)。

        Route.tsx 文件

        import React, { useEffect } from 'react';
        import { Route, RouteProps, useLocation } from 'react-router-dom';
        import API from 'src/services/service';
        
        const CustomRoute = (props: RouteProps) => {
          const location = useLocation();
        
          // Detect Route Change
          useEffect(() => {
            handleRouteChange();
        
            return () => {
              handleRouteComponentUnmount();
            };
          }, [location?.pathname]);
        
          function handleRouteChange() {
            // ...
          }
        
          function handleRouteComponentUnmount() {
            API.finishPendingRequests('RouteChange');
          }
        
          return <Route {...props} />;
        };
        
        export default CustomRoute;
        

        Service.ts 文件

        import { Response } from 'src/models/request';
        import axios, {AxiosInstance, AxiosResponse } from 'axios';
        
        const ORIGIN_URL = 'https://myserver.com'
        const BASE_URL = ORIGIN_URL + '/api';
        let CANCEL_TOKEN_SOURCE = axios.CancelToken.source();
            
        function generateNewCancelTokenSource() {
          CANCEL_TOKEN_SOURCE = axios.CancelToken.source();
        }
        
        export const axiosInstance: AxiosInstance = axios.create({
          baseURL: BASE_URL,
        });
        
        const API = {
          get<DataResponseType = any>(
            endpoint: string,
          ): Promise<AxiosResponse<Response<DataResponseType>>> {
            return axiosInstance.get<Response<DataResponseType>>(endpoint, {
              cancelToken: CANCEL_TOKEN_SOURCE.token,
            });
          },
        
          // ...Another Functions
        
          finishPendingRequests(cancellationReason: string) {
            CANCEL_TOKEN_SOURCE.cancel(cancellationReason);
            generateNewCancelTokenSource();
          },
        };
        
        export default API;
        

        【讨论】:

          猜你喜欢
          • 2021-07-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-14
          相关资源
          最近更新 更多