Javascript 在React功能组件中取消异步axios请求的正确方法

Javascript 在React功能组件中取消异步axios请求的正确方法,javascript,reactjs,axios,Javascript,Reactjs,Axios,在React功能组件中取消异步请求的正确方法是什么? 我有一个脚本,在加载时(或在某些用户操作下)从API请求数据,但如果正在执行此脚本&用户导航离开,则会导致以下警告: 警告:无法对已卸载的组件执行React状态更新。这是一个no-op,但它表示应用程序中存在内存泄漏。要修复此问题,请取消useEffect清理函数中的所有订阅和异步任务 我所读的大部分内容都是通过基于类的组件的componentdidumount方法中的AbortController来解决这个问题的。然而,我的React应用程

在React功能组件中取消异步请求的正确方法是什么?

我有一个脚本,在加载时(或在某些用户操作下)从API请求数据,但如果正在执行此脚本&用户导航离开,则会导致以下警告:

警告:无法对已卸载的组件执行React状态更新。这是一个no-op,但它表示应用程序中存在内存泄漏。要修复此问题,请取消useEffect清理函数中的所有订阅和异步任务

我所读的大部分内容都是通过基于类的组件的
componentdidumount
方法中的
AbortController
来解决这个问题的。然而,我的React应用程序中有一个功能组件,它使用Axis向API发出异步数据请求

该函数位于功能组件中的
useffect
钩子中,以确保在组件呈现以下内容时运行该函数:

useffect(()=>{
加载字段();
},[loadFields]);
这是它调用的函数:

  const loadFields = useCallback(async () => {
    setIsLoading(true);
    try {
      await fetchFields(
        fieldsDispatch,
        user.client.id,
        user.token,
        user.client.directory
      );
      setVisibility(settingsDispatch, user.client.id, user.settings);
      setIsLoading(false);
    } catch (error) {
      setIsLoading(false);
    }
  }, [
    fieldsDispatch,
    user.client.id,
    user.token,
    user.client.directory,
    settingsDispatch,
    user.settings,
  ]);
这是触发的axios请求:


async function fetchFields(dispatch, clientId, token, folder) {
  try {
    const response = await api.get(clientId + "/fields", {
      headers: { Authorization: "Bearer " + token },
    });

    // do something with the response

  } catch (e) {
    handleRequestError(e, "Failed fetching fields: ");
  }
}
注意:
api
变量是对
axios.create
对象的引用。

有一个可以使用的返回选项。它的行为(几乎)与componentDidUnmount相同

useEffect(() => {
  // Your axios call

  return () => {
    // Your abortController
  }
}, []);
有一个您可以使用的返回选项。它的行为(几乎)与componentDidUnmount相同

useEffect(() => {
  // Your axios call

  return () => {
    // Your abortController
  }
}, []);

您可以使用lodash.debounce并尝试以下步骤

Stap 1:

inside constructor:
this.state{
 cancelToken: axios.CancelToken,
 cancel: undefined,
}
this.doDebouncedTableScroll = debounce(this.onScroll, 100);
步骤2: 使用axios add的内部函数:

if (this.state.cancel !== undefined) {
                cancel();
            }
步骤3:

 onScroll = ()=>{
    axiosInstance()
         .post(`xxxxxxx`)
              , {data}, {
                  cancelToken: new cancelToken(function executor(c) {
                         this.setState({ cancel: c });
                        })
                   })
                    .then((response) => {
    
                         }

您可以使用lodash.debounce并尝试以下步骤

Stap 1:

inside constructor:
this.state{
 cancelToken: axios.CancelToken,
 cancel: undefined,
}
this.doDebouncedTableScroll = debounce(this.onScroll, 100);
步骤2: 使用axios add的内部函数:

if (this.state.cancel !== undefined) {
                cancel();
            }
步骤3:

 onScroll = ()=>{
    axiosInstance()
         .post(`xxxxxxx`)
              , {data}, {
                  cancelToken: new cancelToken(function executor(c) {
                         this.setState({ cancel: c });
                        })
                   })
                    .then((response) => {
    
                         }

要使用
axios
取消
fetch
操作:

  • 具有给定源令牌的请求
  • 请确保在卸载组件后不会更改组件状态

  • 广告1。)

    axios
    带来了自己的取消API:

    const source = axios.CancelToken.source();
    axios.get('/user/12345', { cancelToken: source.token })
    source.cancel(); // invoke to cancel request
    
    您可以使用它通过停止一个异步请求来优化性能,这已经不再需要了。如果使用本机浏览器
    fetch
    API,则将改用

    广告2。)

    这将停止警告
    “警告:无法对未安装的组件执行React状态更新。”
    。例如,不能对已卸载的组件调用
    setState
    。是一个执行和封装上述约束的钩子示例


    示例:
    useAxiosFetch
    我们可以将这两个步骤合并到自定义挂钩中:

    function useAxiosFetch(url, { onFetched, onError, onCanceled }) {
      React.useEffect(() => {
        const source = axios.CancelToken.source();
        let isMounted = true;
        axios
          .get(url, { cancelToken: source.token })
          .then(res => { if (isMounted) onFetched(res); })
          .catch(err => {
            if (!isMounted) return; // comp already unmounted, nothing to do
            if (axios.isCancel(err)) onCanceled(err);
            else onError(err);
          });
    
        return () => {
          isMounted = false;
          source.cancel();
        };
      }, [url, onFetched, onError, onCanceled]);
    }
    

    从“React”导入React;
    从“axios”导入axios;
    导出默认函数App(){
    const[mounted,setMounted]=React.useState(true);
    返回(
    {挂载&&}
    setMounted(p=>!p)}>
    {装载?“卸载”:“装载”}
    );
    }
    常数Comp=()=>{
    const[state,setState]=React.useState(“加载…”);
    常量url=`https://jsonplaceholder.typicode.com/users/1?_delay=3000×tamp=${new Date().getTime()}`;
    const handlers=React.usemo(
    () => ({
    onFetched:res=>setState(`Fetched user:${res.data.name}`),
    onCanceled:err=>setState(“请求已取消”),
    onError:err=>setState(“其他错误:”,err.message)
    }),
    []
    );
    const cancel=useAxiosFetch(url,处理程序);
    返回(
    {state}

    {state==“正在加载…”&&( 取消请求 )} ); }; //您可以使用自定义配置参数扩展此挂钩,以获得更多axios选项 函数useAxiosFetch(url,{onFetched,onError,onCanceled}){ const cancelRef=React.useRef(); const cancel=()=>cancelRef.current&&cancelRef.current.cancel(); React.useffect(()=>{ cancelRef.current=axios.CancelToken.source(); 让isMounted=真; axios .get(url,{cancelToken:cancelRef.current.token}) 。然后(res=>{ 如果(isMounted)已获取(res); }) .catch(错误=>{ 如果(!isMounted)return;//comp已卸载,则无需执行任何操作 如果(axios.isCancel(err))被取消(err); 其他错误(err); }); return()=>{ isMounted=错误; 取消(); }; },[url,onFetched,onError,onCanceled]; 返回取消;
    }
    要取消使用
    axios的
    获取操作

  • 具有给定源令牌的请求
  • 请确保在卸载组件后不会更改组件状态

  • 广告1。)

    axios
    带来了自己的取消API:

    const source = axios.CancelToken.source();
    axios.get('/user/12345', { cancelToken: source.token })
    source.cancel(); // invoke to cancel request
    
    您可以使用它通过停止一个异步请求来优化性能,这已经不再需要了。如果使用本机浏览器
    fetch
    API,则将改用

    广告2。)

    这将停止警告
    “警告:无法对未安装的组件执行React状态更新。”
    。例如,不能对已卸载的组件调用
    setState
    。是一个执行和封装上述约束的钩子示例


    示例:
    useAxiosFetch
    我们可以将这两个步骤合并到自定义挂钩中:

    function useAxiosFetch(url, { onFetched, onError, onCanceled }) {
      React.useEffect(() => {
        const source = axios.CancelToken.source();
        let isMounted = true;
        axios
          .get(url, { cancelToken: source.token })
          .then(res => { if (isMounted) onFetched(res); })
          .catch(err => {
            if (!isMounted) return; // comp already unmounted, nothing to do
            if (axios.isCancel(err)) onCanceled(err);
            else onError(err);
          });
    
        return () => {
          isMounted = false;
          source.cancel();
        };
      }, [url, onFetched, onError, onCanceled]);
    }
    

    从“React”导入React;
    从“axios”导入axios;
    导出默认函数App(){
    const[mounted,setMounted]=React.useState(true);
    返回(
    {挂载&&}
    setMounted(p=>!p)}>
    {装载?“卸载”:“装载”}
    );
    }
    常数Comp=()=>{
    const[state,setState]=React.useState(“加载…”);
    常量url=`https://jsonplaceholder.typicode.com/users/1?_delay=3000×tamp=${new Date().getTime()}`;
    const handlers=React.usemo(
    () => ({
    onFetched:res=>setState(`Fetched user:${res.data.name}`),
    onCanceled:err=>setState(“请求已取消”),
    onError:err=>setState(“其他错误:”,err.message)
    }),
    []
    );
    const cancel=useAxiosFetch(url,处理程序);
    返回(
    {state}

    {state==“正在加载…”