使用ReactJS开发秒表后如何实现浏览器刷新时计时数据不丢失
React秒表刷新保留计时数值的实现方案
要实现浏览器刷新后秒表计时不重置,本质是将秒表的核心运行状态持久化存储在浏览器本地,页面重新加载时优先读取本地存储的状态完成初始化即可。
实现步骤
- 第一步:确定需要持久化的核心状态
一共需要存储3个关键字段,避免刷新后逻辑出错:- 累计计时毫秒数:不要存储格式化后的字符串,避免后续转换误差
- 秒表运行状态:标记当前是运行中/暂停/已重置状态
- 最后一次状态更新的时间戳:用于计算刷新期间流逝的时间,保证运行中的秒表刷新后可以自动补全计时
- 第二步:状态变更时同步到本地存储
每次计时更新、运行状态切换时,都将最新状态同步写入localStorage,示例方法:const saveState = (currentState) => { localStorage.setItem('stopwatch_data', JSON.stringify({ ...currentState, lastUpdateTime: Date.now() })) } - 第三步:页面初始化时读取本地存储的状态
组件挂载时优先读取localStorage中的秒表数据,如果是运行中状态,需要先计算刷新期间流失的时间,补到累计计时值后再启动计时器:useEffect(() => { const savedData = localStorage.getItem('stopwatch_data') if (!savedData) return const { totalTime, isRunning, lastUpdateTime } = JSON.parse(savedData) if (isRunning) { // 补算刷新期间的时间差 const offset = Date.now() - lastUpdateTime setTotalTime(totalTime + offset) setIsRunning(true) } else { setTotalTime(totalTime) } }, []) - 第四步:适配重置逻辑
用户点击重置秒表时,除了清空本地state,还要同步删除localStorage中存储的秒表数据,避免下次打开页面加载旧数据。
完整代码示例
import { useState, useEffect, useRef } from 'react' function Stopwatch() { const [totalTime, setTotalTime] = useState(0) const [isRunning, setIsRunning] = useState(false) const timerRef = useRef(null) // 初始化加载本地存储状态 useEffect(() => { const savedData = localStorage.getItem('stopwatch_data') if (!savedData) return const { totalTime: savedTime, isRunning: savedRunning, lastUpdateTime } = JSON.parse(savedData) if (savedRunning) { const offset = Date.now() - lastUpdateTime setTotalTime(savedTime + offset) setIsRunning(true) } else { setTotalTime(savedTime) } }, []) // 状态变更同步到本地存储 useEffect(() => { if (isRunning || totalTime > 0) { localStorage.setItem('stopwatch_data', JSON.stringify({ totalTime, isRunning, lastUpdateTime: Date.now() })) } }, [totalTime, isRunning]) // 计时器运行逻辑 useEffect(() => { if (isRunning) { timerRef.current = setInterval(() => { setTotalTime(prev => prev + 10) }, 10) } else { clearInterval(timerRef.current) } return () => clearInterval(timerRef.current) }, [isRunning]) // 操作方法 const handleStart = () => setIsRunning(true) const handlePause = () => setIsRunning(false) const handleReset = () => { setIsRunning(false) setTotalTime(0) localStorage.removeItem('stopwatch_data') } // 时间格式化,原有逻辑可直接复用 const formatTime = (ms) => { const seconds = Math.floor(ms / 1000) % 60 const minutes = Math.floor(ms / 60000) % 60 const hours = Math.floor(ms / 3600000) return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` } return ( <div className="stopwatch"> <h2>{formatTime(totalTime)}</h2> <button onClick={handleStart} disabled={isRunning}>启动</button> <button onClick={handlePause} disabled={!isRunning}>暂停</button> <button onClick={handleReset}>重置</button> </div> ) } export default Stopwatch
注意事项
- 本地存储仅支持同一浏览器同一设备的状态持久化,如果需要跨设备同步,可以把存储逻辑替换为后端接口读写
- localStorage存储的是字符串,读写时需要做JSON序列化和反序列化处理
- 如果使用React18严格模式,开发环境下useEffect会执行两次,属于框架正常行为,不影响生产环境运行
内容的提问来源于stack exchange,提问作者Aswin.S
相关产品推荐
相关产品推荐

