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

React.memo包裹的函数组件仍重复渲染问题求助

问题分析与解决方案

核心问题1:QuestionComponent 定义位置错误

你把QuestionComponent定义在了Game组件内部,每次Game因为timer更新而重渲染时,这个组件都会被重新定义成一个全新的函数。这直接导致React.memo完全失效——React会认为这是一个不同的组件类型,必然会重新渲染它,不管有没有memo包裹。

核心问题2:定时器实现存在闭包与重复创建问题

你的useEffect依赖了timer,这意味着每秒timer更新时,都会销毁旧定时器并创建新的。而且setTimer(timer - 1000)用的是闭包中的timer值,在某些情况下可能出现计时偏差。


修复后的代码

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

// 把QuestionComponent移到Game外部,保证组件引用稳定
const QuestionComponent = memo(props => {
  return(<div><input type="text" placeholder="答题输入框"/></div>);
});

function Game() {
  const [timer, setTimer] = useState(180000);
  
  useEffect(() => {
    // 仅在组件挂载时创建一次定时器
    const interval = setInterval(() => {
      // 使用函数式更新,直接获取最新状态值,避免闭包问题
      setTimer(prevTimer => {
        if (prevTimer <= 0) {
          clearInterval(interval);
          return 0;
        }
        return prevTimer - 1000;
      });
    }, 1000);

    return () => clearInterval(interval);
  }, []); // 空依赖数组,确保只执行一次

  return (
    <>
      <div>{Math.floor(timer / 1000)}秒</div>
      <QuestionComponent/>
    </>
  );
}

关键改动说明

  • 组件移至外部:QuestionComponent现在在Game外部定义,每次Game重渲染时,它的引用不会改变,React.memo就能正常工作——只有当它的props变化时才会重新渲染。
  • 定时器优化:
    • 依赖数组改为空,只在组件挂载时创建一次定时器,避免每秒重复创建销毁的冗余操作。
    • 使用setTimer(prevTimer => ...)的函数式更新,直接获取最新的状态值,解决闭包导致的计时错误。
    • 增加计时到0时自动清除定时器的逻辑,避免无效循环。

这样修改后,QuestionComponent不会再每秒重复渲染,移动端输入框反复失焦闪烁的问题也会随之解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 02:30:49