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

React 18严格模式下Axios重复请求的解决方法

解决React 18严格模式下Axios请求重复发起的问题

在React 18严格模式中,组件会经历挂载→卸载→重新挂载的过程,这会导致componentDidMount执行两次。你原本用state中的dataFetched做判断,但第二次挂载时state会重置为初始值,所以这个判断无法阻止重复请求。以下是几种可靠的解决方案:

方案1:使用类组件实例变量标记请求状态

实例变量不会随组件卸载重置,能有效避免重复发起请求:

修改你的代码,在constructor中添加一个实例变量标记请求是否已发起,然后在componentDidMount中判断这个变量:

import React, { Component } from "react";
import axios from "axios";
import history from "../../history";

class Authenticate extends Component {
   constructor(props) {
       super(props);
       this.state = {
           token: "",
           dataFetched: false,
       };
       // 添加实例变量标记请求状态
       this.isRequestInitiated = false;
       this.getCallBack = this.getCallBack.bind(this);
   }
   async componentDidMount() {
       // 判断实例变量,而非state
       if (!this.isRequestInitiated) {
           this.isRequestInitiated = true; // 标记请求已发起
           try {
               const res = await axios({
                   method: "get",
                   url: "/users/twitter_login",
               });
               if (res.data.boolean) {
                   this.setState({ dataFetched: true, token: res.data.token });
                   this.getCallBack(res.data.url);
               } else {
                   history.push({
                       pathname: "/login",
                   });
               }
           } catch (error) {
               console.log(error);
               // 请求失败时可以重置标记,允许重试
               this.isRequestInitiated = false;
           }
       }
   }

   getCallBack(url) {
       history.push(url);
   }

   render() {
       return (
           <div>
               <img src="http://placekitten.com/g/200/300"></img>
           </div>
       );
   }
}

export default Authenticate;

方案2:使用Axios取消令牌(CancelToken)

如果需要更精细的控制(比如取消重复的未完成请求),可以用Axios的取消机制:

import React, { Component } from "react";
import axios from "axios";
import history from "../../history";

class Authenticate extends Component {
   constructor(props) {
       super(props);
       this.state = {
           token: "",
           dataFetched: false,
       };
       this.cancelTokenSource = null;
       this.getCallBack = this.getCallBack.bind(this);
   }

   componentDidMount() {
       if (!this.cancelTokenSource) {
           this.cancelTokenSource = axios.CancelToken.source();
           axios({
               method: "get",
               url: "/users/twitter_login",
               cancelToken: this.cancelTokenSource.token
           }).then((res) => {
               if (res.data.boolean) {
                   this.setState({ dataFetched: true, token: res.data.token });
                   this.getCallBack(res.data.url);
               } else {
                   history.push({
                       pathname: "/login",
                   });
               }
           }).catch((error) => {
               if (axios.isCancel(error)) {
                   console.log("请求已取消", error.message);
               } else {
                   console.log(error);
                   this.cancelTokenSource = null; // 失败后重置,允许重试
               }
           });
       }
   }

   componentWillUnmount() {
       // 组件卸载时取消未完成的请求
       if (this.cancelTokenSource) {
           this.cancelTokenSource.cancel("组件卸载,取消请求");
       }
   }

   getCallBack(url) {
       history.push(url);
   }

   render() {
       return (
           <div>
               <img src="http://placekitten.com/g/200/300"></img>
           </div>
       );
   }
}

export default Authenticate;

补充:迁移到函数组件的方案

如果后续考虑升级到函数组件,可以用useRef保存请求状态,配合useEffect实现单次请求:

import React, { useEffect, useRef, useState } from "react";
import axios from "axios";
import history from "../../history";

const Authenticate = () => {
    const [token, setToken] = useState("");
    const [dataFetched, setDataFetched] = useState(false);
    const isRequestInitiated = useRef(false);

    useEffect(() => {
        if (!isRequestInitiated.current) {
            isRequestInitiated.current = true;
            const fetchData = async () => {
                try {
                    const res = await axios({
                        method: "get",
                        url: "/users/twitter_login",
                    });
                    if (res.data.boolean) {
                        setDataFetched(true);
                        setToken(res.data.token);
                        history.push(res.data.url);
                    } else {
                        history.push("/login");
                    }
                } catch (error) {
                    console.log(error);
                    isRequestInitiated.current = false;
                }
            };
            fetchData();
        }
    }, []);

    return (
        <div>
            <img src="http://placekitten.com/g/200/300"></img>
        </div>
    );
};

export default Authenticate;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 09:50:24