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

React番茄钟应用切换标签后,如何持续更新页面标题?

解决React番茄钟后台标签标题跳变问题

核心思路

放弃依赖setInterval每秒更新状态的方式,改用记录起始时间戳+实时计算耗时的方案。浏览器后台节流的是定时器,但系统时间会持续推进,通过时间差计算能得到准确耗时,避免标题跳变。

具体实现步骤

  • 存储起始时间戳:工作模式启动时,将当前时间戳(Date.now())存入状态,同时标记工作状态(isWorking)。
  • 替换定时器逻辑:用setInterval或requestAnimationFrame触发更新,但每次更新都通过当前时间与起始时间的差值计算真实耗时,而非依赖累计的每秒状态更新。
  • 绑定计算后的耗时到标题:通过React Helmet直接绑定计算出的分秒格式耗时,确保切回标签时显示准确值。

代码示例

import { useState, useEffect, useRef } from 'react';
import { Helmet } from 'react-helmet';

const PomodoroTimer = () => {
  const [isWorking, setIsWorking] = useState(false);
  const [startTime, setStartTime] = useState(null);
  const [elapsedTime, setElapsedTime] = useState(0);
  const timerRef = useRef(null);

  // 格式化毫秒为mm:ss格式
  const formatTime = (ms) => {
    const totalSeconds = Math.floor(ms / 1000);
    const minutes = String(Math.floor(totalSeconds / 60)).padStart(2, '0');
    const seconds = String(totalSeconds % 60).padStart(2, '0');
    return `${minutes}:${seconds}`;
  };

  useEffect(() => {
    if (isWorking) {
      // 启动时记录起始时间
      setStartTime(Date.now());
      // 定时器每秒触发,但每次都计算真实时间差
      timerRef.current = setInterval(() => {
        const currentElapsed = Date.now() - startTime;
        setElapsedTime(currentElapsed);
      }, 1000);
    } else {
      clearInterval(timerRef.current);
    }

    return () => clearInterval(timerRef.current);
  }, [isWorking, startTime]);

  return (
    <>
      <Helmet>
        <title>{isWorking ? `Work - ${formatTime(elapsedTime)}` : '番茄钟'}</title>
      </Helmet>
      <button onClick={() => setIsWorking(!isWorking)}>
        {isWorking ? '停止工作' : '开始工作'}
      </button>
    </>
  );
};

export default PomodoroTimer;

进阶优化

如果想让切回标签时的更新更及时,可以用requestAnimationFrame替代setInterval,它在标签激活后会立即触发更新:

useEffect(() => {
  if (isWorking) {
    setStartTime(Date.now());
    const updateElapsed = () => {
      const currentElapsed = Date.now() - startTime;
      setElapsedTime(currentElapsed);
      timerRef.current = requestAnimationFrame(updateElapsed);
    };
    timerRef.current = requestAnimationFrame(updateElapsed);
  } else {
    cancelAnimationFrame(timerRef.current);
  }

  return () => cancelAnimationFrame(timerRef.current);
}, [isWorking, startTime]);

这种方案的核心是不依赖定时器的累计更新,每次都基于系统时间计算真实耗时,无论浏览器是否节流定时器,切回标签时都能直接显示正确的耗时,和谷歌秒表的实现逻辑一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:57:14