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> ); }
关键修改点说明
从localStorage初始化状态
改用函数式useState初始化,优先读取localStorage中保存的计时器数据,确保刷新后能恢复之前的进度。自动保存到localStorage
添加专门的useEffect监听countdown变化,每次状态更新时自动将数据存入localStorage,避免手动管理存储逻辑。修复计时useEffect的依赖
给计时逻辑的useEffect添加[countdown.expirityTime, focus]依赖数组,避免组件每次渲染都重复创建定时器,同时保证时间或焦点变化时能正确触发计时。优化Redux dispatch逻辑
将dispatch(timerEnd)移到单独的useEffect中,仅在计时器时间变化时触发,避免组件渲染时重复分发动作。优化焦点监听逻辑
使用addEventListener替代直接赋值window.onblur/onfocus,并在组件卸载时移除监听,防止内存泄漏。补零优化(可选)
给秒数添加补零逻辑,避免出现1:5这类不规范的时间显示。
内容的提问来源于stack exchange,提问作者Muhammad Naveed Nawab
相关产品推荐
相关产品推荐

