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

如何让Snackbar的进度条在消息关闭前到达末端?

问题解决:Snackbar进度条未完成就提前关闭

问题根源

你的代码里用setInterval(100ms)更新进度条,计时到4秒时直接调用handleClose关闭消息。但React状态更新是异步的,进度条还没来得及渲染到100%,组件就已经被卸载,导致视觉上进度条没走完就关闭。另外,innerProgress >=100 && elapsedTime >= duration的判断条件冗余,且100ms的定时器间隔会让进度动画不够流畅,进一步放大了异步渲染的时间差问题。

修复方案

修改GenericSnackbarMessage中的useEffect逻辑,确保进度条渲染到100%后再关闭消息,同时优化动画流畅度:

useEffect(() => {
  if (!closeMessageAfterTime || !activeTimer || !isLastElement) return;

  const startTime = Date.now();
  const duration = 4000;
  let timerId: NodeJS.Timeout;

  const updateProgress = (): void => {
    const currentTime = Date.now();
    const elapsedTime = currentTime - startTime;
    // 强制进度不超过100
    const innerProgress = Math.min((elapsedTime / duration) * 100, 100);

    setProgress(innerProgress);

    if (elapsedTime >= duration) {
      clearInterval(timerId);
      // 延迟50ms关闭,给进度条足够渲染时间
      setTimeout(() => {
        handleClose();
      }, 50);
    }
  };

  // 改用16ms间隔,接近60fps,动画更流畅
  timerId = setInterval(updateProgress, 16);

  return (): void => {
    clearInterval(timerId);
  };
}, [closeMessageAfterTime, activeTimer, isLastElement, handleClose]);

额外优化说明

  1. 优化定时器间隔:16ms是浏览器60帧每秒的理想间隔,让进度条动画更平滑,减少视觉卡顿。
  2. 强制进度上限:用Math.min确保进度值不会超过100,避免出现异常数值。
  3. 延迟关闭逻辑:计时结束后先清除定时器,再延迟50ms调用关闭方法,确保进度条的100%状态被渲染到页面后,再关闭Snackbar。
  4. 简化判断条件:移除innerProgress >=100的判断,因为当elapsedTime >= duration时,innerProgress必然等于100,逻辑更简洁。

其他注意点

Provider中的isLastElement逻辑是正确的:当新消息加入队列时,原最后一条消息的isLastElement会变为false,此时该消息的定时器会被清除,停止自动关闭倒计时,符合队列式Snackbar仅最后一条自动关闭的预期行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:34:55