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

如何在React中实现API请求触发的连续流畅进度加载条

问题原因

你的代码遇到了React的闭包陷阱:changePercent函数在首次触发时,捕获的是当时的loading、loadingPercent状态快照,后续状态更新后,函数内部拿到的还是旧的初始值,所以只会执行一次setPercent(1),后续调用因为判断的旧值永远符合条件但不会更新到新的进度,看起来就卡住了。同时你没有对requestAnimationFrame的回调做清理,也会导致内存泄漏和异常执行。

修复方案

1. 解决闭包与重复调用问题

用useRef存储最新的状态和回调ID,避免闭包捕获旧值,同时添加清理逻辑:

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

// 你的组件内逻辑
const [loadingPercent, setPercent] = useState(0)
// 用ref存最新状态,避免闭包问题
const loadingRef = useRef(loading)
const rafIdRef = useRef(null)

// 同步loading状态到ref
useEffect(() => {
  loadingRef.current = loading
}, [loading])

useEffect(() => {
  if (loading) {
    setPercent(0)
    changePercent()
  } else {
    // 请求结束直接拉满进度,给用户完成反馈
    setPercent(100)
    // 清理动画帧回调
    if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current)
    // 可选:300ms后隐藏进度条,方便用户看到完成状态
    setTimeout(() => {
      // 你的进度条隐藏逻辑
    }, 300)
  }

  // 组件卸载时清理回调,避免内存泄漏
  return () => {
    if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current)
  }
}, [loading])

const changePercent = () => {
  // 用ref的最新状态判断
  if (!loadingRef.current) return
  
  // 函数式更新percent,不依赖外部状态
  setPercent(prev => {
    return prev < 99 ? prev + 1 : 0
  })

  // 存储回调ID方便后续清理
  rafIdRef.current = requestAnimationFrame(changePercent)
}

2. 实现流畅的连续动画效果

如果要做到和示例一致的丝滑效果,不要固定每次加1,而是根据时间差计算增量,适配不同设备的刷新率,同时可以调整增速逻辑,越接近99%增速越慢,更符合真实请求的感知:

// 新增时间记录ref
const lastTimeRef = useRef(Date.now())

const changePercent = () => {
  if (!loadingRef.current) return

  const now = Date.now()
  // 计算两次动画帧的时间差
  const deltaTime = now - lastTimeRef.current
  lastTimeRef.current = now

  // 按10秒走完0-99的速度计算增量,可自行调整系数修改速度
  const increment = (deltaTime / 10000) * 99

  setPercent(prev => {
    const newVal = prev + increment
    // 最高到99%,请求结束后再拉满到100%
    return newVal >= 99 ? 99 : newVal
  })

  rafIdRef.current = requestAnimationFrame(changePercent)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 19:24:04