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

React.js中如何防止页面刷新时计时器重置?

解决方案

你的代码主要存在几个导致刷新后计时器重置的问题,以下是修复后的完整代码及关键修改说明:

修复后代码

import React, { useState, useEffect } from "react";
import { useDispatch } from "react-redux";
import { timerEnd } from "./states-manager/timer-slice";

export default function Timer() {
  // 初始化时从localStorage读取保存的计时器状态,无则用默认值
  const [countdown, setCountdown] = useState(() => {
    const savedTimer = localStorage.getItem('timer');
    return savedTimer ? JSON.parse(savedTimer) : {
      expirityTime: 100,
      expired: false
    };
  });

  const [focus, setFocus] = useState(true);
  const dispatch = useDispatch();

  // 监听标签页焦点变化
  useEffect(() => {
    const handleBlur = () => setFocus(false);
    const handleFocus = () => setFocus(true);

    window.addEventListener('blur', handleBlur);
    window.addEventListener('focus', handleFocus);

    return () => {
      window.removeEventListener('blur', handleBlur);
      window.removeEventListener('focus', handleFocus);
    };
  }, []);

  // 核心计时逻辑:时间>0且页面聚焦时每秒递减
  useEffect(() => {
    if (countdown.expirityTime <= 0 || !focus) return;

    const timerId = setTimeout(() => {
      setCountdown(prev => ({
        ...prev,
        expirityTime: prev.expirityTime - 1,
        expired: prev.expirityTime - 1 <= 0
      }));
    }, 1000);

    return () => clearTimeout(timerId);
  }, [countdown.expirityTime, focus]);

  // 计时器状态变化时,自动保存到localStorage
  useEffect(() => {
    localStorage.setItem('timer', JSON.stringify(countdown));
  }, [countdown]);

  // 将计时器值同步到Redux
  useEffect(() => {
    dispatch(timerEnd(countdown.expirityTime));
  }, [countdown.expirityTime, dispatch]);

  return (
    <div className="App">
      <div className="timer">
        Time Remaining: {Math.floor(countdown.expirityTime / 60)}:
        {countdown.expirityTime % 60 < 10 ? `0${countdown.expirityTime % 60}` : countdown.expirityTime % 60}
      </div>
    </div>
  );
}

关键修改点说明

  1. 从localStorage初始化状态
    改用函数式useState初始化,优先读取localStorage中保存的计时器数据,确保刷新后能恢复之前的进度。

  2. 自动保存到localStorage
    添加专门的useEffect监听countdown变化,每次状态更新时自动将数据存入localStorage,避免手动管理存储逻辑。

  3. 修复计时useEffect的依赖
    给计时逻辑的useEffect添加[countdown.expirityTime, focus]依赖数组,避免组件每次渲染都重复创建定时器,同时保证时间或焦点变化时能正确触发计时。

  4. 优化Redux dispatch逻辑
    将dispatch(timerEnd)移到单独的useEffect中,仅在计时器时间变化时触发,避免组件渲染时重复分发动作。

  5. 优化焦点监听逻辑
    使用addEventListener替代直接赋值window.onblur/onfocus,并在组件卸载时移除监听,防止内存泄漏。

  6. 补零优化(可选)
    给秒数添加补零逻辑,避免出现1:5这类不规范的时间显示。

内容的提问来源于stack exchange,提问作者Muhammad Naveed Nawab

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 10:55:14