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

React倒计时组件触发RandomBoard每秒重渲染问题求助

解决倒计时触发RandomBoard组件重复渲染问题

问题根源

  1. CountDown组件定时器逻辑缺陷:CountDown中的useEffect未设置依赖数组,导致组件每次渲染都会重新创建定时器。每秒执行的tick函数会调用settimeleft更新父组件timeleft状态,触发WordSearchContainer重渲染,进而带动RandomBoard跟着重渲染。
  2. RandomBoard未做渲染优化:即使组件props没有变化,只要父组件重渲染,RandomBoard就会无条件重新渲染。

解决方案

1. 修复CountDown组件的定时器与状态更新逻辑

修改CountDown.js,给useEffect添加正确的依赖数组,同时优化状态更新方式,避免不必要的父组件状态触发:

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

function CountDown({ hours, minutes, seconds, settimeleft, className, extraclass, over, setOver }) {
    const [paused, setPaused] = useState(false);
    const [[h, m, s], setTime] = useState([hours, minutes, seconds]);

    const tick = () => {
        if (paused || over) return;
        if (h === 0 && m === 0 && s === 0) {
            setOver(true);
            settimeleft(0);
        } else {
            setTime(prev => {
                const [ph, pm, ps] = prev;
                let newH = ph, newM = pm, newS = ps;
                
                if (pm === 0 && ps === 0) {
                    newH = ph - 1;
                    newM = 59;
                    newS = 59;
                } else if (ps === 0) {
                    newM = pm - 1;
                    newS = 59;
                } else {
                    newS = ps - 1;
                }
                
                // 基于当前计算的剩余时间更新父组件状态
                settimeleft(newH * 3600 + newM * 60 + newS);
                return [newH, newM, newS];
            });
        }
    };

    useEffect(() => {
        const timerID = setInterval(tick, 1000);
        return () => clearInterval(timerID);
    }, [over, paused]); // 仅在over或paused变化时重建定时器

    return (
        <div className={className}>
            {!over && <p className={`font-weight-bold ${extraclass}`}>{`Time Left ${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`}</p>}
            {over && <span className='text-white bg-danger py-2 mb-2 px-2'>Time up </span>}
        </div>
    );
}

export default CountDown;

2. 给RandomBoard添加渲染优化

使用React.memo包裹RandomBoard组件,只有当props发生变化时才会重渲染:

import React from 'react';

const WordSearchBoard = React.memo(({ setIsStarted }) => {
    return (
        <div className='gameArea mx-4 p-2 row'>
            {Math.random(9,999)}
        </div>
    );
});

export default WordSearchBoard;

3. 优化父组件的副作用逻辑

完善WordSearchContainer的useEffect依赖,避免无效触发:

import React, { useEffect, useState, forwardRef, useImperativeHandle } from 'react'
import CountDown from './CountDown';
import WordSearchBoard from './RandomBoard';

const WordSearchContainer = forwardRef(({ timer, data, entryId, hours, minutes, seconds }, ref) => {
    const [show, setShow] = useState(false);
    const [timeleft, settimeleft] = useState(timer);
    const [over, setOver] = useState(false);
    const [score, setscore] = useState(0);
    const [isStarted, setIsStarted] = useState(true);

    // 补充原代码中未定义的函数(需根据业务逻辑实现)
    const UpdateQuizEntryTimerLeft = () => {
        // 这里填写更新倒计时的业务逻辑
    };

    useEffect(() => {
        if (timer > 0 && timeleft === 0) {
            settimeleft(0);
            UpdateQuizEntryTimerLeft();
            setTimeout(() => setShow(true), 1000);
        }
    }, [timeleft, timer]); // 添加timer依赖,避免无效触发

    useImperativeHandle(ref, () => ({
        UpdateTimerLeft() {
            UpdateQuizEntryTimerLeft();
            return true;
        }
    }));

    return (
        <>
            {(timer && isStarted) ? (
                <CountDown 
                    hours={hours} 
                    minutes={minutes} 
                    seconds={seconds} 
                    settimeleft={settimeleft} 
                    over={over} 
                    setOver={setOver} 
                    className='text-center text-danger' 
                    extraclass="" 
                />
            ) : null}
            <WordSearchBoard setIsStarted={setIsStarted} />
        </>
    );
});

WordSearchContainer.displayName = "WordSearchContainer";

export default WordSearchContainer;

关键说明

  • 给CountDown的useEffect添加依赖数组,避免每秒重复创建定时器,减少不必要的状态更新。
  • React.memo会对RandomBoard的props进行浅比较,只有props变化时才触发重渲染,阻止父组件重渲染带来的无效更新。
  • 优化settimeleft的调用逻辑,基于组件内部状态的前值计算,避免依赖外部传入的timeleft导致的更新错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:07:04