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

Next.js中使用setInterval实现进度条组件遇到的问题

问题分析与解决方案

核心问题拆解

你的代码存在几个关键问题导致异常:

  • 直接修改State变量:progress++直接修改了useState返回的state变量,违反React state不可变原则,会导致组件状态混乱,甚至出现未触发点击就异常更新的情况。
  • 闭包捕获旧值:handleClick中的progress是组件初始渲染时的闭包值,后续interval里的if (progress == 100)永远不会成立,因为闭包不会捕获更新后的state,导致interval无法停止,最终进度条直接拉满。
  • 未正确管理Interval生命周期:没有处理组件卸载时的interval清除,可能引发内存泄漏。

修复后的代码

import React, { useState, useRef, useEffect } from "react";

const ProgressBar = () => {
  const [progress, setProgress] = useState(1);
  const intervalRef = useRef(null); // 用useRef保存interval ID,避免闭包问题

  // 组件卸载时清除interval,防止内存泄漏
  useEffect(() => {
    return () => {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
      }
    };
  }, []);

  const handleClick = () => {
    // 点击前先清除已有interval,避免重复点击触发多个动画
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
    }
    // 重置进度到初始值
    setProgress(1);
    
    intervalRef.current = setInterval(() => {
      setProgress(prevProgress => {
        // 每次更新前判断是否达到100,达到则清除interval
        if (prevProgress >= 100) {
          clearInterval(intervalRef.current);
          return 100;
        }
        return prevProgress + 1;
      });
    }, 100);
  };

  return (
    <>
      <div className="bg-gray-300 w-full">
        <div className={`h-[30px] w-[${progress}%] bg-green-500 transition-all duration-100`}></div>
      </div>
      <button 
        onClick={handleClick}
        className="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
      >
        点击开始
      </button>
    </>
  );
};

export default ProgressBar;

关键修复点说明

  • 函数式State更新:使用setProgress(prevProgress => ...)确保每次拿到最新的state值,避免闭包导致的旧值问题。
  • useRef管理Interval ID:用useRef存储interval ID,确保在组件生命周期内可以正确访问和清除它,不受闭包影响。
  • Interval生命周期管理:通过useEffect的清理函数,在组件卸载时自动清除interval,防止内存泄漏。
  • 重复点击处理:点击按钮时先清除已有interval,避免多个动画同时运行。
  • 平滑过渡优化:给进度条加上transition-all duration-100类,让进度变化更自然(可选优化)。

关于DOM操作的注意事项

React中应尽量避免直接操作DOM,因为React的虚拟DOM会管理视图更新,手动DOM操作容易导致状态与视图不一致。如果确实需要操作DOM,应该使用useRef获取DOM元素引用,而非document.getElementById,避免在组件未挂载或元素不存在时出现引用错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 18:52:29