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

React中双定时器无法正常执行 求实现循环倒计时流程

问题修复:循环倒计时与输入框显示流程

核心错误梳理

  1. CountDown组件render语法错误:return后直接换行触发JS自动分号插入,导致组件无渲染内容,控制台报错。
  2. componentDidUpdate参数错误:该方法第一个参数是prevProps,第二个才是prevState,原代码把prevProps当成prevState使用,导致倒计时结束的判断逻辑失效。
  3. CountDown无重置机制:父组件状态变化重新传入duration时,组件不会重置倒计时数值,无法实现循环触发。
  4. App组件语法与逻辑漏洞:
    • JSX缺少根包裹元素,语法报错;
    • onChange函数未定义;
    • 状态更新是异步的,直接打印canType会拿到旧值;
    • 无循环重启timer1的逻辑,timer2结束后流程终止。

修复后的完整代码

CountDown.js

import React from 'react';

export default class CountDown extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: props.duration ?? 5,
        }
    }

    // 监听props变化,重置倒计时
    static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.duration !== prevState.count) {
            return { count: nextProps.duration };
        }
        return null;
    }

    componentDidMount() {
        this.startTimer();
    }

    componentDidUpdate(prevProps, prevState) {
        // 倒计时结束时清除定时器并触发回调
        if (prevState.count !== this.state.count && this.state.count === 0) {
            clearInterval(this.timer);
            this.props.onTimesup?.();
        }
        // 当props的duration变化时,重启定时器
        if (prevProps.duration !== this.props.duration) {
            clearInterval(this.timer);
            this.startTimer();
        }
    }

    componentWillUnmount() {
        clearInterval(this.timer); // 组件卸载时清除定时器,避免内存泄漏
    }

    startTimer() {
        this.timer = setInterval(() => {
            this.setState(prevState => ({
                count: prevState.count - 1
            }));
        }, 1000);
    }

    fmtMSS(s) {
        const minutes = Math.floor(s / 60);
        const seconds = s % 60;
        return `${minutes}:${seconds.toString().padStart(2, '0')}`;
    }

    render() {
        const { count } = this.state;
        return <div>{this.fmtMSS(count)}</div>;
    }
}

App.js

import React, { useState } from 'react';
import CountDown from './CountDown';

const App = () => {
    const [canType, setCanType] = useState(0);
    const [restartKey, setRestartKey] = useState(0);

    const onTimer1End = () => {
        setCanType(1);
        setTimeout(() => console.log("timer1 结束,canType:", canType), 0);
    };

    const onTimer2End = () => {
        setCanType(0);
        setTimeout(() => {
            console.log("timer2 结束,canType:", canType);
            // 通过修改key强制重启timer1
            setRestartKey(prev => prev + 1);
        }, 0);
    };

    const onChange = (e) => {
        console.log("输入内容:", e.target.value);
    };

    return (
        <div className="box d">
            {canType === 0 && (
                <CountDown 
                    key={restartKey} 
                    onTimesup={onTimer1End} 
                    duration={2} 
                />
            )}
            {canType === 1 && (
                <>
                    <input type="text" onChange={onChange} />
                    <CountDown onTimesup={onTimer2End} duration={5} />
                </>
            )}
        </div>
    );
};

export default App;

修复说明

  1. CountDown组件:
    • 新增getDerivedStateFromProps监听duration变化,重置倒计时数值;
    • 提取startTimer方法复用定时器启动逻辑;
    • 修复componentDidUpdate参数顺序,确保判断逻辑正确;
    • 新增componentWillUnmount清除定时器,避免内存泄漏;
    • 修复render方法的语法错误,添加倒计时文本渲染。
  2. App组件:
    • 通过修改key强制重启timer1,实现循环流程;
    • 补充onChange函数,避免控制台报错;
    • 用setTimeout异步打印最新状态,解决异步更新的旧值问题;
    • 用<>包裹同级JSX元素,修复根元素问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:45:44