React中使用requestAnimationFrame更新对象属性时列表被清空问题
问题解决:requestAnimationFrame更新时清空humans列表
问题根源
animate函数在组件初始化时被useEffect调用,形成闭包捕获了初始状态的空humans数组。后续每次执行requestAnimationFrame时,都会基于这个空数组调用setHumans,导致新添加的人类被覆盖清空。
修复方案
- 使用函数式更新状态:调用
setHumans时传入回调函数,直接获取最新的状态值,避免闭包陷阱 - 修正类型导入错误:移除错误的
import IHuman from './Human',类型已在组件内定义 - 移除子组件冗余key:
key属性应在父组件的map循环中设置,子组件无需重复定义
修改后的代码
World.tsx
import { useState, useEffect } from 'react' import Human from './Human' type IHuman = { id: number; x: number; y: number; color: string; } export default function World() { const [humans, setHumans] = useState<IHuman[]>([]) const addHuman = () => { setHumans(prevHumans => [...prevHumans, {id: Math.random(), x: 0, y: 0, color: 'red'}]) } const animate = () => { // 使用函数式更新,获取最新的humans状态 setHumans(prevHumans => prevHumans.map(human => ({...human, x: human.x + 1})) ); requestAnimationFrame(animate); } useEffect(() => { const animationId = requestAnimationFrame(animate); // 组件卸载时取消动画,避免内存泄漏 return () => cancelAnimationFrame(animationId); }, []); return ( <> <button onClick={addHuman}>new human</button> <main> {humans.map(human => ( <Human key={human.id} x={human.x} y={human.y} color={human.color} /> ))} </main> </> ) }
Human.tsx
export default function Human(props: { id: number; x: number; y: number; color: string; }) { return ( <div className="human" style={{ top: `${props.y}px`, left: `${props.x}px`, backgroundColor: props.color }} > {props.id} </div> ) }
额外优化说明
- 给
Human组件添加了明确的类型定义,替代原有的any类型,提升类型安全性 - 在
useEffect中添加了动画取消逻辑,防止组件卸载后动画继续运行导致内存泄漏 addHuman也改用函数式更新,确保在并发更新场景下的状态正确性
内容的提问来源于stack exchange,提问作者GIA
相关产品推荐
相关产品推荐

