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

React使用Axios渲染ApexCharts出现卸载组件更新状态报错如何解决

问题原因及修复方案

你遇到的警告是因为组件卸载后,仍有未完成的异步请求执行完毕后尝试更新组件状态导致的,你的代码存在3个核心问题:

  • 挂载状态变量命名不一致:constructor和componentDidMount中你使用的是this._isMount,但componentWillUnmount里写的是this._isMounted,变量名不匹配导致挂载标记完全失效
  • 没有在组件卸载时触发Axios请求取消:你已经创建了CancelToken实例,但没有在componentWillUnmount中调用source.cancel()方法终止未完成的请求
  • 嵌套的子请求没有做挂载状态校验:你在循环中发起的获取项目阶段的异步请求回调中,没有判断组件是否已挂载就操作数据、触发状态更新,即使主请求做了校验,子请求返回时组件也可能已经卸载

修正后的完整代码

import React, {Component} from "react";
import GridWrapper from "../helpers/gridWrapper";
import Chart from 'react-apexcharts'
import ContentWrapper from "../helpers/contentWrapper";
import GridWrapperL from "../helpers/twoSideBySideWrapper/gridWrapperL";
import axios from "axios";

export default class Charts extends Component{
  constructor(props) {
    super(props);
    // 统一挂载状态命名
    this._isMounted = false;
    // 把source挂载到实例上,避免全局变量污染
    this.source = axios.CancelToken.source();
    this.state = {
      options: {
        chart: {
          id: 'apexchart-example'
        },
        xaxis: {
          categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999]
        }
      },
      series: [
        {
          name: '',
          data: [],
        },
        { 
          name:"In progress stages",
          data:[],
        },
        { 
          name:"Completed stages",
          data:[],
        }
      ]
    }
  }

  async componentDidMount(){
    this._isMounted = true;
    const todoARR=[] ; const inProgressArr=[]; const readyArr=[];
    const project_name=[];

    try {
      //获取项目详情
      const projectRes = await axios.get('http://localhost:5000/api/projects',  {
        cancelToken: this.source.token
      });
      const data = projectRes.data.projects; 

      // 用Promise.all等待所有子请求完成,避免异步顺序问题
      await Promise.all(data.map(async (element) => {
        project_name.push(element.projectName);
        const stageRes = await axios.get(`http://localhost:5000/api/auth/stages/findproject/projectId?id=${element._id}` , {
          cancelToken: this.source.token
        });
        const data2 = stageRes.data.stage;
        var todo=0; var inprogress=0; var done=0;

        //收集每个项目的阶段信息
        data2.forEach(element2 => { 
          if(element2.status == "TO-DO"){
            todo = todo+1;
          }
          if(element2.status == "IN-PROGRESS"){
            inprogress = inprogress+1;
          }
          if(element2.status == "READY"){
            done=done+1;
          }
        })
        todoARR.push(todo);
        inProgressArr.push(inprogress);
        readyArr.push(done);
      }))

      //设置Apex图表数据,先判断组件是否挂载
      if(this._isMounted){
        this.setState({
          options: {
            chart: {
              id: 'apexchart-example'
            },
            xaxis:{
              categories:project_name,
            }
          },
          series: [
            {
              name: 'Todo stages',
              data: todoARR,
            },
            { 
              name:"In progress stages",
              data:inProgressArr,
            },
            { 
              name:"Completed stages",
              data:readyArr,
            }
          ]
        })
      }
    } catch(err) {
      // 如果是请求取消的报错,不打印日志
      if (!axios.isCancel(err)) {
        console.log("error", err)
      }
    }
  }

  componentWillUnmount() {
    this._isMounted = false;
    // 取消所有未完成的请求
    this.source.cancel('组件卸载,终止未完成请求');
  }
 
  render(){
    return(
      <center>
        <div>
          {/* 只需修改type属性值为line即可切换为折线图 */}
          <Chart options={this.state.options} series={this.state.series} type="bar" width={1000} height={520} />
        </div>
      </center>
    );
  }
};

额外优化说明

把原来forEach嵌套异步请求的逻辑改成了Promise.all等待所有子请求全部返回后再统一更新状态,既避免了多次触发状态更新的性能问题,也解决了异步请求返回顺序不一致导致的数据错乱问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 01:27:03