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
相关产品推荐
相关产品推荐

