如何阻止React飞船组件中函数因重复渲染频繁调用?
问题根源
你遇到的核心问题是重复绑定事件监听:
- 每次组件状态更新(比如修改坐标后),组件会重新渲染,而你的代码在渲染阶段直接执行
window.addEventListener,导致同一个keydown事件被绑定了成百上千个相同的监听函数。 - 按下方向键时,所有绑定的监听都会触发,次数随着渲染次数指数级增长,最终引发性能问题甚至崩溃。
解决步骤
1. 用useEffect管理事件的绑定与解绑
把事件监听逻辑放到useEffect中,设置空依赖数组,确保只在组件挂载时绑定一次,卸载时自动解绑,避免重复绑定。
2. 使用函数式更新避免闭包问题
因为监听函数只会绑定一次,直接使用horizontalCords会捕获初始状态值,后续状态更新后无法拿到最新值。改用函数式更新(setHorizontalCords(prev => prev - 10)),直接基于上一次状态计算新值。
修正后的代码
import { useState, useEffect } from "react"; import { constants } from "../../constants"; import "./space-ship.styles.css"; export const Spaceship = (): JSX.Element => { const [horizontalCords, setHorizontalCords] = useState<number>(0); const [verticalCords, setVerticalCords] = useState<number>(0); const validateArrowKey = (key: KeyboardEvent): void => { console.log("called one"); if (key.keyCode === 37) { setHorizontalCords(prev => prev - 10); return; } else if (key.keyCode === 39) { setHorizontalCords(prev => prev + 10); } else if (key.keyCode === 38) { setVerticalCords(prev => prev - 10); } else if (key.keyCode === 40) { setVerticalCords(prev => prev + 10); } }; useEffect(() => { window.addEventListener("keydown", validateArrowKey); // 组件卸载时移除监听,防止内存泄漏 return () => { window.removeEventListener("keydown", validateArrowKey); }; }, []); // 空依赖数组,仅在组件挂载/卸载时执行 return ( <img style={{ left: `${horizontalCords}px`, top: `${verticalCords}px` }} className="space-ship" src={constants.space_ship} alt="Space ship" /> ); };
额外优化建议
- 替换
keyCode为key属性(keyCode已被标准废弃),比如判断key === "ArrowLeft"、key === "ArrowRight"等,代码可读性更强且符合现代标准。 - 可添加防抖逻辑(比如用
setTimeout),避免长按方向键时触发过于频繁的状态更新,进一步优化性能。
内容的提问来源于stack exchange,提问作者Fernando Rodrigues
相关产品推荐
相关产品推荐

