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

React页面刷新时不重置Timeout:按钮禁用状态续期问题

解决按钮禁用状态持久化与倒计时续期问题

你的代码目前存在两个核心问题:

  • 按钮禁用状态disable未存入localStorage,页面刷新后会重置为初始值
  • 倒计时的剩余时间没有记录,刷新后定时器会重新从5秒开始

下面是修改后的完整代码,可同时解决这两个问题:

import React, { useEffect, useState, useRef } from 'react'

function Without() {
  const [count, _setCountValue] = useState(3);
  const [disable, setDisable] = useState(false);
  const timeoutRef = useRef(null); // 用ref保存定时器ID,避免组件重渲染丢失

  // 封装同时更新state和localStorage的计数方法
  function setCount(value) {
    localStorage.setItem('count', JSON.stringify(value));
    return _setCountValue(value);
  }

  // 同步更新禁用状态到localStorage
  function setDisableState(value) {
    localStorage.setItem('disable', JSON.stringify(value));
    setDisable(value);
  }

  // 保存倒计时结束的时间戳到localStorage
  function setResetTime(timestamp) {
    localStorage.setItem('resetTime', timestamp);
  }

  const handleDec = () => {
    if (count > 1) {
      setCount(count - 1);
    } else {
      setCount(0);
      setDisableState(true);
      // 计算倒计时结束的时间戳(当前时间+5秒)
      const resetTimestamp = Date.now() + 5000;
      setResetTime(resetTimestamp);
      // 设置定时器
      timeoutRef.current = setTimeout(() => {
        setDisableState(false);
        setCount(3);
        localStorage.removeItem('resetTime'); // 倒计时结束清空记录
      }, 5000);
    }
  };

  useEffect(() => {
    // 初始化时读取localStorage中的所有持久化数据
    const storedCount = localStorage.getItem('count');
    const storedDisable = localStorage.getItem('disable');
    const storedResetTime = localStorage.getItem('resetTime');

    // 恢复计数状态
    if (storedCount) {
      setCount(parseInt(storedCount));
    }

    // 恢复禁用状态
    if (storedDisable) {
      setDisable(JSON.parse(storedDisable));
    }

    // 处理剩余倒计时:如果存在未过期的重置时间,计算剩余时长并重启定时器
    if (storedResetTime) {
      const now = Date.now();
      const remainingTime = parseInt(storedResetTime) - now;
      if (remainingTime > 0) {
        timeoutRef.current = setTimeout(() => {
          setDisableState(false);
          setCount(3);
          localStorage.removeItem('resetTime');
        }, remainingTime);
      } else {
        // 倒计时已结束,直接恢复初始状态
        setDisableState(false);
        setCount(3);
        localStorage.removeItem('resetTime');
      }
    }

    // 组件卸载时清理定时器,避免内存泄漏
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
    };
  }, []);

  return (
    <div>
      <h3>{count} / 3</h3>
      <button disabled={disable} onClick={handleDec}>
        Remaining Use
      </button>
    </div>
  )
}

export default Without

关键修改说明:

  • 新增setDisableState方法,同步将禁用状态写入localStorage,解决刷新后状态重置问题
  • 用时间戳记录倒计时结束时间,而非依赖定时器本身,刷新后可通过当前时间与记录时间的差值计算剩余时长
  • 使用useRef存储定时器ID,确保组件重渲染或卸载时能正确清理定时器
  • 初始化阶段检查倒计时记录,自动续期未完成的计时逻辑
  • 组件卸载时清理定时器,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:52:58