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

React中Timer子组件倒计时结束后如何传递状态更新父组件参数

解决方案

问题根因

  • React 规定props为只读属性,子组件直接修改传入的props不会生效,也无法触发父组件状态更新和重渲染
  • 现有Timer组件仅接收了状态值,没有接收父组件的状态更新回调,无法反向通知父组件修改状态
  • 原有倒计时结束判断使用difference === 0,受定时器精度影响可能出现漏触发的情况

修改步骤

1. 修改Timer组件,新增过期回调

调整组件入参,删除没用的isValid属性,新增onExpire回调用于通知父组件倒计时结束,同时优化结束判断逻辑:

import React, { useEffect, useState } from "react";
import "./Timer.scss";

interface ITimerProps {
  // 倒计时结束回调
  onExpire: () => void;
}

export const Timer = ({ onExpire }: ITimerProps) => {
  const [minutes, setMinutes] = useState(0);
  const [seconds, setSeconds] = useState(0);
  const tokenTTL = 10;

  useEffect(() => {
    const actualTime = new Date();
    const target = new Date(
      actualTime.setMinutes(actualTime.getMinutes() + tokenTTL)
    );

    const interval = setInterval(() => {
      const now = new Date();
      const difference = target.getTime() - now.getTime();

      // 倒计时结束处理
      if (difference <= 0) {
        clearInterval(interval);
        onExpire();
        setMinutes(0);
        setSeconds(0);
        return;
      }

      let m: string | number = Math.floor(
        (difference % (1000 * 60 * 60)) / (1000 * 60)
      );
      m = m < 10 ? "0" + m : m;
      setMinutes(m as number);

      let s: string | number = Math.floor((difference % (1000 * 60)) / 1000);
      s = s < 10 ? "0" + s : s;
      setSeconds(s as number);
    }, 1000);
    return () => clearInterval(interval);
  }, [onExpire]);

  return (
    <div className="Timer">
      <div className="Timer__Container">
        <div className="Timer-content">
          <span className="minutes">{minutes}</span>
        </div>
        <span className="divider">:</span>
        <div className="Timer-content">
          <span className="seconds">{seconds}</span>
        </div>
      </div>
    </div>
  );
};

2. 调整useLoginByCode自定义hook,暴露状态修改方法

在hook内部把isCodeExpired对应的修改方法暴露出来,同时刷新验证码的时候重置过期状态:

export const useLoginByCode = () => {
  // 原有逻辑保留
  const [isCodeExpired, setIsCodeExpired] = useState(false);

  const refreshCode = () => {
    // 原有刷新验证码逻辑保留
    setIsCodeExpired(false); // 刷新验证码时重置过期状态
  }

  return {
    // 原有返回的字段保留
    isCodeExpired,
    setIsCodeExpired, // 新增暴露状态修改方法
    refreshCode,
    // 其他返回字段保留
  }
}

3. 调整Login父组件调用逻辑

解构获取状态修改方法,给Timer组件传递过期回调:

// 解构时新增setIsCodeExpired
const { code, refreshCode, isCodeExpired, setIsCodeExpired, refresh, error, loading } = useLoginByCode();

渲染Timer的部分调整为:

{/* 新增key属性,每次code刷新时自动重启倒计时 */}
<Timer onExpire={() => setIsCodeExpired(true)} key={code} />

额外优化说明

  • 给Timer加key={code}属性,每次验证码刷新时组件自动重新挂载,无需额外编写重置倒计时的逻辑
  • 倒计时结束后主动清除定时器,避免无用的定时器继续运行占用资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 16:45:03