你以为动画卡是 Reanimated 有 bug?今天发现其实是 Shadow Tree 的节点从来没人清理

Discord 迁移 React Native 新架构后,Android 动画帧率直接掉了一半。团队找了一圈,结论是:这不是谁的 bug,是 Reanimated 和 Fabric 的 Shadow Tree 交互方式里藏着一个没人注意的泄漏。

动画卡成 PPT,不是代码的错

2025 年底,Discord 的 Android App 完成了向 React Native 新架构(Fabric)的迁移。功能正常,但动画体验断崖式下跌。工程经理后来的描述很直接:「感觉像 2006 年的 PowerPoint」。

Discord 大量使用 Reanimated 做交互动画,所以问题焦点很快锁定在 Reanimated 与 Fabric 的配合上。

根因:每帧多克隆了几百个节点

Margelo 团队介入诊断后发现,Reanimated 的 cloneShadowTreeWithNewProps 函数在每一帧都会把当前所有处于追踪状态的动画节点的 Shadow Tree 完整克隆一遍。

问题在于:动画播放完毕后,节点从未被注销。也就是说,哪怕屏幕上 100 个动画元素里只有 1 个正在动,Reanimated 也会把这 100 个节点的 Shadow Tree 全量克隆一次。每帧几百次节点克隆,Android 渲染管线就这样被拖垮了。

这个行为在旧架构(Bridge)下被其他因素掩盖,迁移 Fabric 后才暴露出来。

两个特征开关,把泄漏堵上了

Margelo 提出的修复绕开 Shadow Tree 的克隆路径,核心是两个 feature flag:

FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS(Reanimated v4.3.0+ 默认开启):动画稳定后主动将状态同步回 React 层,使节点可从内部 props registry 提前注销,不再参与每帧克隆。

ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS:恢复非布局属性(opacity、transform 等)的同步更新快速路径,跳过 Shadow Tree 的完整提交流程。

效果实测:Discord Android 的 jank frame rate 降低了 26%,恢复到新架构优化前的水平。

0.85 把这个修法直接写进了框架

Margelo 和 Meta 合作把这次修复的机制推进了 React Native 核心,叫「Shared Animation Backend」,随 React Native 0.85(2026 年 4 月)以 feature flag 形式提供。后续 Reanimated 的内部实现会逐步迁移到这个共享引擎上,进一步减少两个动画系统之间的重复维护。

你的项目有没有这个问题

如果你也在用 Reanimated + Fabric,遇到 Android 端动画莫名卡顿,可以先查两件事:

  1. Reanimated 版本是否 ≥ 4.3.0(FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS 默认开启)
  2. 是否可以手动加上 ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS 这个 flag

对于新项目,升级到 React Native 0.85+ 并启用 Shared Animation Backend 是推荐路径。这次不是优化,是 Bug 修复——框架本身不该让开发者承担这个代价。

评论区

0 条评论

登录后可评论。

阿跨·跨端开发 1819 阅读