网易首页 > 网易号 > 正文 申请入驻

React程序员做小游戏,60帧下setState直接崩了

0
分享至


一个前端工程师用React写游戏,帧率掉到个位数时,他意识到问题不在代码,而在框架的「肌肉记忆」。

这是@nyaomaru的真实经历。他拿到了NVIDIA送的《生化危机9》,到现在还没见到第一只僵尸——但他在浏览器里做的小游戏《Run Away From Work》,却让他对React有了完全不同的理解。

游戏看起来很简单:一个打工鱼逃跑,老板追,路上捡鱼币躲障碍。但当他试图用setState驱动每一帧动画时,浏览器风扇开始狂转。

setState → 重渲染 → diff → DOM更新,这套流程在60fps下就是性能自杀。

他没有换框架,而是换了一套架构思路。React还在,但游戏循环(Game Loop)被彻底剥离出去。

React的渲染模型,和游戏循环是两种生物

React的核心假设是:状态变了,UI重新计算。这对表单、列表、仪表盘是完美的。

但游戏不一样。游戏需要每16.6毫秒更新一次画面,而且更新的往往不是整棵树,是几十个实体的坐标。用React的diff算法处理这个,就像用Excel公式做实时渲染——能跑,但何必。

@nyaomaru的解法很直接:React只负责静态结构,动态实体直接操作DOM。

看这段代码。游戏区域由React渲染,但玩家、老板、障碍物这些「活物」,全是原生DOM节点。

他用document.createElement生成障碍物,用appendChild塞进游戏区域,用requestAnimationFrame驱动位置更新。React完全不知道这些节点存在。

这听起来像「反模式」,但性能数据不会骗人。浏览器主线程从「喘不过气」变成「游刃有余」,帧率稳在60fps。

三层架构:React当骨架,原生DOM当肌肉

具体实现分三层。最外层是React的领地:游戏容器、UI覆盖层、分数显示。这些很少变动,React处理得干净利落。

中间层是实体管理层。@nyaomaru用useRef保存所有动态元素的引用,但绝不把它们塞进state。障碍物数组存在ref里,React渲染周期永远看不到它们。

最内层是动画循环。requestAnimationFrame每帧直接修改DOM节点的style.transform,跳过React的调和(Reconciliation)全过程。

这种「混合模式」的关键是隔离。React管它的,原生DOM管它的,两者通过ref建立单向联系。React知道游戏区域在哪里,但不知道里面有多少个障碍物在飞。

一个细节:玩家和老板的精灵图也是SVG,但位置更新不走React。sprite的transform属性被直接赋值,浏览器合成层(Compositor)接手后续工作,主线程零负担。

为什么不用Canvas?

读到这你可能会问:都操作原生DOM了,为什么不直接用Canvas 2D或WebGL?

@nyaomaru考虑过,但拒绝了。他的理由是工具链和审美:所有视觉素材都是Adobe Illustrator手绘的SVG,保留DOM结构意味着可以用CSS做响应式、用浏览器开发者工具直接调试、用现成的无障碍支持。

更重要的是,这个游戏的复杂度还没到Canvas的甜点区。几十个移动元素,DOM+CSS transform完全吃得消。Canvas的优势在成千上万个粒子,这里用不上。

这选择里有产品经理的权衡思维。技术选型不是选「最强」的,是选「刚刚好」的。为了10%的性能提升,牺牲50%的开发体验和可维护性,这笔账不划算。

从游戏循环看框架边界

这个案例的真正价值,是展示了如何在一个React应用里「开天窗」。

框架的渲染模型是契约。React的契约是「声明式UI,我帮你同步状态和视图」。但游戏循环的契约是「每帧直接写屏,延迟必须低于16ms」。两份契约冲突时,强行套用一方就是灾难。

@nyaomaru的做法是承认边界:React负责「结构稳定但数据多变」的部分,原生DOM负责「结构多变但数据简单」的部分。这不是对React的否定,是对其适用域的清醒认知。

他甚至在GitHub上开源了完整代码。评论区最热的反馈是:「原来useRef还能这么用」——很多人把ref当成「避免重渲染的逃生舱」,却忘了它本身就是通往DOM的合法通道。

另一个有趣的点是状态管理。分数、游戏阶段这些「业务状态」仍在React里,用useState完全没问题。但实体的位置、速度、碰撞箱这些「物理状态」,被隔离在React之外,用纯JavaScript对象管理。

这种分层让调试变得直观。游戏逻辑bug看控制台,UI bug看React DevTools,互不干扰。

性能数字背后的真相

没有公开的benchmark,但@nyaomaru描述了一个典型场景:30个障碍物同时移动,纯React方案帧率掉到15fps,混合方案稳60fps。

差距来自哪里?React的调和算法在每次setState时要遍历组件树,计算最小更新。30个障碍物意味着30次状态变更,或者1次批量变更但涉及30个组件。无论哪种,开销都远高于直接修改30个DOM节点的transform。

更隐蔽的成本是垃圾回收。频繁创建和销毁React元素会产生大量临时对象,触发GC时帧率波动。原生DOM方案的对象生命周期简单得多。

这些细节在普通应用里无关紧要,但在帧时间预算只有16ms的游戏里,每一毫秒都是战场。

给前端工程师的启示

这个案例最实用的 takeaway 是:学会在React应用里「作弊」。

useRef、createPortal、甚至直接操作DOM,这些「逃生舱」不是bug,是框架设计者预留的应急通道。当你确定某个场景不在React的甜点区时,果断绕路比强行优化更聪明。

另一个启示是关于技术写作的。@nyaomaru的文章结构很典型:先展示问题(帧率崩溃),再展示解法(架构分层),最后给可运行的代码。没有抽象的理论,全是具体的决策点和权衡。

这种写法对25-40岁的技术读者特别有效——他们经历过足够多的项目,知道「最佳实践」往往在边界处失效,想看到的是别人怎么在真实约束下做取舍。

最后提一个产品细节。游戏里的「老板」角色有一个手臂动画,用CSS关键帧实现。这个动画完全独立于游戏循环,由浏览器合成层处理,不占用主线程。

@nyaomaru在文章结尾说,他还没通关《生化危机9》,因为「看到第一个僵尸就关了游戏」。但他的小游戏已经让几百人摸鱼时多了一种选择——如果React的渲染模型没有把他逼到墙角,这个解法可能永远不会被写出来。

你现在手上有多少个「本该用React做」的场景,其实更适合直接操作DOM?

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
RIP!罗马尼亚80岁老帅因病去世:12天前率队无缘世界杯 气晕住院

RIP!罗马尼亚80岁老帅因病去世:12天前率队无缘世界杯 气晕住院

风过乡
2026-04-08 04:55:06
古代为何很少发生强奸案?难道古人都很正派吗?原因其实很简单

古代为何很少发生强奸案?难道古人都很正派吗?原因其实很简单

芳芳历史烩
2026-04-06 22:50:52
向华强首谈大哥去世:ICU拖了9个月花掉数百万,一堆护士照顾他

向华强首谈大哥去世:ICU拖了9个月花掉数百万,一堆护士照顾他

开开森森
2026-04-08 09:29:12
骗走50亿!用小鲜肉的血抗衰,被央视曝光的“捞金女王”,真栽了

骗走50亿!用小鲜肉的血抗衰,被央视曝光的“捞金女王”,真栽了

往史过眼云烟
2026-04-07 22:23:40
空篮都上不进!“辽篮樱木”11分钟0分1板,球迷:白瞎这么大个子

空篮都上不进!“辽篮樱木”11分钟0分1板,球迷:白瞎这么大个子

弄月公子
2026-04-07 22:42:02
伊朗公布停火声明,令人泪目!给了8800万伊朗民众一个交代

伊朗公布停火声明,令人泪目!给了8800万伊朗民众一个交代

共工之锚
2026-04-08 14:27:06
离谱!皇马1.5亿巨星浪费超级单刀放生拜仁 失误致丢球仍摊手抱怨

离谱!皇马1.5亿巨星浪费超级单刀放生拜仁 失误致丢球仍摊手抱怨

我爱英超
2026-04-08 05:38:05
安徽女童遇害后续,父亲回应传闻,3大疑点曝光,细节越扒越残忍

安徽女童遇害后续,父亲回应传闻,3大疑点曝光,细节越扒越残忍

青橘罐头
2026-04-08 07:33:23
国家体育总局回应全红婵遭网暴:已联合开展核查处置 全红婵所属训练中心已向警方报案

国家体育总局回应全红婵遭网暴:已联合开展核查处置 全红婵所属训练中心已向警方报案

闪电新闻
2026-04-08 14:45:59
“过期也不用扔”的7样东西,扔掉就是浪费,放家里妙用太多了!

“过期也不用扔”的7样东西,扔掉就是浪费,放家里妙用太多了!

Home范
2026-04-08 09:51:55
中国正式向全世界宣告:解放军打日本不用获得任何人的同意授权

中国正式向全世界宣告:解放军打日本不用获得任何人的同意授权

聊历史的阿稼
2026-04-08 05:25:30
WTI原油期货跌幅扩大至19%

WTI原油期货跌幅扩大至19%

证券时报
2026-04-08 07:44:04
CBA正在“杀死”中国男篮!6大乱象不除,我们过不了日韩这一关

CBA正在“杀死”中国男篮!6大乱象不除,我们过不了日韩这一关

蛋疼体育
2026-04-07 17:54:23
陈丽华去世仅2天,小11岁老公过往被扒,原来他和翁帆的处境一样

陈丽华去世仅2天,小11岁老公过往被扒,原来他和翁帆的处境一样

做一个合格的吃瓜群众
2026-04-07 20:43:53
女子穿坏6.8万紫貂后续:底裤被扒,真容曝光已社死,工作恐不保

女子穿坏6.8万紫貂后续:底裤被扒,真容曝光已社死,工作恐不保

阿纂看事
2026-04-07 12:02:19
陈丽华66岁儿子赵勇担任富华国际集团总裁,是陈丽华和前夫所生

陈丽华66岁儿子赵勇担任富华国际集团总裁,是陈丽华和前夫所生

观鱼听雨
2026-04-07 17:58:37
海豚疯狂的繁殖行为!它们和人类一样,不以生育为目的进行性行为

海豚疯狂的繁殖行为!它们和人类一样,不以生育为目的进行性行为

怪罗
2026-04-05 22:14:48
理想高管“隔空喊话”张雪:这台三缸机 凭什么能解决“卡脖子”?

理想高管“隔空喊话”张雪:这台三缸机 凭什么能解决“卡脖子”?

趣味萌宠的日常
2026-04-07 17:23:14
中国男篮国手王俊杰宣布将转校 感谢过去3年在旧金山大学的时光

中国男篮国手王俊杰宣布将转校 感谢过去3年在旧金山大学的时光

醉卧浮生
2026-04-08 09:45:09
张钧甯与导演男友西班牙度假,两人气质好搭,交往2年多见过父母

张钧甯与导演男友西班牙度假,两人气质好搭,交往2年多见过父母

白面书誏
2026-04-08 14:03:32
2026-04-08 15:23:00
碳基打工人
碳基打工人
坐标北京,靠咖啡续命,靠小红书下饭的普通人类。
971文章数 6关注度
往期回顾 全部

科技要闻

造出地表最强AI,却死活不给你用!

头条要闻

美联社:伊朗同意停火前中国出面介入 万斯也参与斡旋

头条要闻

美联社:伊朗同意停火前中国出面介入 万斯也参与斡旋

体育要闻

40岁,但实力倒退12年

娱乐要闻

杨颖邓超低调现身观众席 支持陈赫话剧

财经要闻

特朗普同意停火两周 伊朗:接受停火提议

汽车要闻

5门5座/新复古造型 缤果Pro将于4月14日开启预售

态度原创

艺术
时尚
家居
本地
军事航空

艺术要闻

齐白石『凌波仙子』

阔腿裤失宠了?今年这几条裤子最时髦!

家居要闻

自在恣意 侘寂风别墅

本地新闻

跟着歌声游安徽,听古村回响

军事要闻

文化符号当“弹药” 美伊将信息战带入新阶段

无障碍浏览 进入关怀版