reactjs - 在 React Hooks useEffect 清理失败中取消 Axios REST 调用

标签 reactjs axios react-hooks

我显然没有正确清理并取消 axios GET 请求,我应该这样做。在我本地,我收到一条警告,内容为

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

在 stackblitz 上,我的代码可以工作,但由于某种原因我无法单击按钮来显示错误。它总是显示返回的数据。

https://codesandbox.io/s/8x5lzjmwl8

请检查我的代码并找出我的缺陷。

使用AxiosFetch.js

import {useState, useEffect} from 'react'
import axios from 'axios'

const useAxiosFetch = url => {
    const [data, setData] = useState(null)
    const [error, setError] = useState(null)
    const [loading, setLoading] = useState(true)

    let source = axios.CancelToken.source()
    useEffect(() => {
        try {
            setLoading(true)
            const promise = axios
                .get(url, {
                    cancelToken: source.token,
                })
                .catch(function (thrown) {
                    if (axios.isCancel(thrown)) {
                        console.log(`request cancelled:${thrown.message}`)
                    } else {
                        console.log('another error happened')
                    }
                })
                .then(a => {
                    setData(a)
                    setLoading(false)
                })
        } catch (e) {
            setData(null)
            setError(e)
        }

        if (source) {
            console.log('source defined')
        } else {
            console.log('source NOT defined')
        }

        return function () {
            console.log('cleanup of useAxiosFetch called')
            if (source) {
                console.log('source in cleanup exists')
            } else {
                source.log('source in cleanup DOES NOT exist')
            }
            source.cancel('Cancelling in cleanup')
        }
    }, [])

    return {data, loading, error}
}

export default useAxiosFetch

index.js

import React from 'react';

import useAxiosFetch from './useAxiosFetch1';

const index = () => {
    const url = "http://www.fakeresponse.com/api/?sleep=5&data={%22Hello%22:%22World%22}";
    const {data,loading} = useAxiosFetch(url);

    if (loading) {
        return (
            <div>Loading...<br/>
                <button onClick={() => {
                    window.location = "/awayfrom here";
                }} >switch away</button>
            </div>
        );
    } else {
        return <div>{JSON.stringify(data)}xx</div>
    }
};

export default index;

最佳答案

这是最终的代码,一切正常,以防其他人回来。

import {useState, useEffect} from "react";
import axios, {AxiosResponse} from "axios";

const useAxiosFetch = (url: string, timeout?: number) => {
    const [data, setData] = useState<AxiosResponse | null>(null);
    const [error, setError] = useState(false);
    const [errorMessage, setErrorMessage] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        let unmounted = false;
        let source = axios.CancelToken.source();
        axios.get(url, {
            cancelToken: source.token,
            timeout: timeout
        })
            .then(a => {
                if (!unmounted) {
                    // @ts-ignore
                    setData(a.data);
                    setLoading(false);
                }
            }).catch(function (e) {
            if (!unmounted) {
                setError(true);
                setErrorMessage(e.message);
                setLoading(false);
                if (axios.isCancel(e)) {
                    console.log(`request cancelled:${e.message}`);
                } else {
                    console.log("another error happened:" + e.message);
                }
            }
        });
        return function () {
            unmounted = true;
            source.cancel("Cancelling in cleanup");
        };
    }, [url, timeout]);

    return {data, loading, error, errorMessage};
};

export default useAxiosFetch;

关于reactjs - 在 React Hooks useEffect 清理失败中取消 Axios REST 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53861916/

相关文章:

javascript - 使用 System.import 或 require.ensure 响应代码拆分和服务器端渲染

axios - 如何在axios中获取响应状态码?标准解决方案不起作用

javascript - 未捕获的类型错误 : Cannot read properties of undefined (reading 'url' )

javascript - JavaScript 中的对象引用比较

javascript - React 默认调用不带括号的函数 useState

javascript - react enzyme 试验

javascript - 当我的数据是 bool 值时,在 mui-datatables 的 switch 中显示表数据

javascript - React PropTypes 的多重验证

node.js - 启用 CORS - Node.js + React/Redux + Axios 部署在 Heroku 上

javascript - 使用 setinterval 更新功能组件中的状态