React开发Chrome同款恐龙跑酷游戏时setInterval触发快于设置值问题
React开发恐龙跑酷游戏定时器触发频率异常排查
我正在用React开发一款类似谷歌Chrome内置的恐龙跑酷游戏。
我的思路是在障碍物预计与恐龙发生碰撞的时刻(约3秒)运行对应检测函数,代码如下:
function check4Death() { if (playerClass !== '') { console.log('safe') } else { console.log('nope') clearInterval() } } setInterval(check4Death, 3000)
该函数用于检测玩家当前是否处于空中:我的跳跃实现方式是给playerClass对象添加jump类,之后再移除该类,跳跃功能的代码如下:
function Jump() { setPlayerClass('jump') setTimeout(() => { setPlayerClass('') }, 500); }
但实际运行时,该函数没有按照预期每3秒输出一次safe或nope,反而触发频率远高于设置值,运行效果见下图:
问题根因
- 定时器重复创建:你将
setInterval直接写在了React函数组件的顶层作用域中,只要组件触发重渲染(比如playerClass状态更新),就会重新执行组件逻辑,新建一个定时器。运行时间越长,并行的定时器数量越多,触发频率自然远高于设定的3秒间隔。 - 清除逻辑无效:
clearInterval调用必须传入对应定时器的ID作为参数,你当前的调用没有传参,就算触发else分支也不会清除任何运行中的定时器。 - 缺少销毁逻辑:组件卸载时没有主动清除定时器,会造成内存泄漏。
修复方案
使用useEffect+useRef管理定时器,确保全局仅存在一个碰撞检测定时器,参考代码如下:
import { useEffect, useRef, useState } from 'react' function DinoGame() { const [playerClass, setPlayerClass] = useState('') // 用useRef存储定时器ID,跨渲染周期保持取值稳定 const collisonTimerRef = useRef(null) // 组件首次挂载时初始化定时器 useEffect(() => { collisonTimerRef.current = setInterval(check4Death, 3000) // 组件卸载时清除定时器,避免内存泄漏 return () => clearInterval(collisonTimerRef.current) }, []) function check4Death() { if (playerClass !== '') { console.log('safe') } else { console.log('nope') // 传入定时器ID完成清除 clearInterval(collisonTimerRef.current) } } function Jump() { // 增加跳跃状态判断,避免重复触发跳跃 if (playerClass === 'jump') return setPlayerClass('jump') setTimeout(() => { setPlayerClass('') }, 500) } // 剩余组件渲染逻辑省略 }
内容的提问来源于stack exchange,提问作者Dylan Bozarth
相关产品推荐
相关产品推荐

