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

React动态环形进度条组件异常:第二个进度条静止求助

问题描述

我开发了一个独立的动态环形ProgressBar组件,在Dashboard组件中放置了两个该组件实例。其中第一个进度条运行正常,但第二个始终静止在0%且未调用进度函数。注:我使用了Tailwindcss。请帮忙修复该问题。

Dashboard组件代码

import React, { Component } from 'react'
import { connect } from 'react-redux';
import { getUserInfo } from '../actions/userActions';
import { Link } from 'react-router-dom';
import ProgressBar from './progressBar';

class Dashboard extends Component {

    state = {
        user: {

        }
    }

    componentDidMount(){
        this.props.getUserInfo();
        this.setState({
          user : this.props.currentUser
        })
    }

  render() {

    const { user } = this.state;


    return (
      <div className='w-full h-auto bg-slate-100 p-4'>

        { (user?.isLoggedIn == true) ? <div className='dashboard'>
          <div className='w-full flex h-auto mt-14'>

            <div className='border-2 border-slate-500 relative block text-center w-9/2 md:w-1/5 md:min-w-72 h-56 md:h-72 mr-2 mx-auto rounded-md'>
              <h1 className='balance text-2xl font-medium w-auto mx-auto mt-9 md:mt-20 md:font-semibold'>Personal balance</h1>
              <h1 className="balance text-3xl mt-6">0 $</h1>
            </div>
            <div className='border-2 border-slate-500 relative flex w-9/2 md:w-4/5 h-56 md:h-72 mx-auto rounded-md'>

            </div>

          </div>
          <div className='mt-2 p-2 border-2 border-slate-500 relative flex justify-between w-full h-56 md:h-64 mx-auto rounded-md'>
            <div className='w-28 h-28 md:w-36 md:h-36'>
              <ProgressBar percentage={99} />
            </div>
            <div className='w-28 h-28 md:w-36 md:h-36'>
              <ProgressBar percentage={99} />
            </div>
          </div>

        </div> : 

        // NOT LOGGED PAGE

        <div className='w-full h-screen block mt-24'>
          <h1 className="text-xl text-red-500">You are not logged yet</h1>
          <Link to="log-in"> Login here </Link>
        </div>
        }
      </div>
    )
  }
}

const mapUserStateToProps = (state) => {
    return {
        currentUser : state.user.user
    }
}

export default connect(mapUserStateToProps, { getUserInfo })(Dashboard);

ProgressBar组件代码

import React, { Component } from 'react'

class ProgressBar extends Component {


  render() { 

      let progressContainer = document.querySelector('.progress-container');
      let valueContainer = document.querySelector('.progress-value');
      const speed = 20;
      let progressValue = 0;
      //let progressEndValue = 70;


      function updateElements() {
        valueContainer = document.querySelector('.progress-value');
        progressContainer = document.querySelector('.progress-container');
      }

      const createProgress = setInterval(() => {
        updateElements();
        valueContainer.innerText = `${progressValue} %`
        progressContainer.style.background = `conic-gradient(
          rgb(239 68 68) ${progressValue*3.6}deg,
          black 1deg,
          rgb(251, 202, 202)  1deg
          )`
          
          if (progressValue == this.props.percentage) {
            clearInterval(createProgress);
          }
          progressValue++;
        }, speed) 

    return (
      <div className='progress-container w-full h-full rounded-full flex justify-center items-center'>
        <div className="w-3/4 h-3/4 rounded-full bg-slate-100 flex justify-center items-center">
            <h1 className='progress-value' >0 %</h1>
        </div>
      </div>
    ) 
  }
}


export default ProgressBar;

问题原因

  • 全局DOM选择器冲突:document.querySelector只会返回页面中第一个匹配的DOM元素,第二个ProgressBar实例无法获取到自己对应的容器和数值元素,只能操作第一个实例的DOM。
  • render函数内创建定时器:render函数会在组件更新时重复执行,每次执行都会新建定时器,导致逻辑混乱、内存泄漏,且无法精准控制每个实例的进度流程。

修复方案

重构ProgressBar组件

使用React状态管理+Ref操作组件内部DOM,将定时器逻辑移至生命周期函数中:

import React, { Component, createRef } from 'react'

class ProgressBar extends Component {
  constructor(props) {
    super(props);
    this.state = {
      progressValue: 0
    };
    // 创建Ref绑定组件内部容器
    this.progressContainerRef = createRef();
    this.timer = null;
  }

  // 组件挂载后启动进度动画
  componentDidMount() {
    this.startProgress();
  }

  // 组件卸载前清除定时器,避免内存泄漏
  componentWillUnmount() {
    if (this.timer) {
      clearInterval(this.timer);
    }
  }

  startProgress() {
    const speed = 20;
    const target = this.props.percentage;

    this.timer = setInterval(() => {
      this.setState(prevState => {
        const nextValue = prevState.progressValue + 1;
        // 到达目标值时停止定时器
        if (nextValue >= target) {
          clearInterval(this.timer);
          return { progressValue: target };
        }
        return { progressValue: nextValue };
      }, () => {
        // 状态更新后更新容器样式
        if (this.progressContainerRef.current) {
          this.progressContainerRef.current.style.background = `conic-gradient(
            rgb(239 68 68) ${this.state.progressValue * 3.6}deg,
            black 1deg,
            rgb(251, 202, 202) 1deg
          )`;
        }
      });
    }, speed);
  }

  render() { 
    return (
      <div 
        ref={this.progressContainerRef}
        className='progress-container w-full h-full rounded-full flex justify-center items-center'
      >
        <div className="w-3/4 h-3/4 rounded-full bg-slate-100 flex justify-center items-center">
            <h1 className='progress-value'>{this.state.progressValue} %</h1>
        </div>
      </div>
    ) 
  }
}

export default ProgressBar;

额外优化:Dashboard组件的用户状态同步

原代码中componentDidMount直接同步Redux状态可能会因为异步请求未完成导致数据错误,改为监听props变化:

componentDidMount(){
  this.props.getUserInfo();
}

componentDidUpdate(prevProps) {
  // 当Redux中的用户信息更新时,同步到组件state
  if (prevProps.currentUser !== this.props.currentUser) {
    this.setState({
      user: this.props.currentUser
    });
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:20:42