用 react-native-best-practices 给 AI 助手装上 RN 性能优化手册

前言

React Native 应用变慢,原因通常不在某一行代码。列表卡顿、冷启动超过两秒、包体积被 barrel import 悄悄撑大、内存随页面来回泄漏——这些问题会同时出现在 JS 线程、原生层和打包链路里。排查时如果只靠零散博客,很容易先改 useMemo、再换状态库,最后发现帧率和启动时间几乎没动。

Callstack 把这类经验先写成了面向人的电子书 The Ultimate Guide to React Native Optimization,2026 年 1 月又把它拆成 Agent Skill:react-native-best-practices。装进 Cursor、Claude Code、Codex 这类 AI 编程工具后,助手在做性能审查或改 RN / Expo 代码时,会按优先级去读对应的参考文档,而不是凭印象给一堆通用建议。

本文按官方仓库、SKILL.md 原文和 Callstack 公告核对后整理:这个 Skill 是什么、覆盖哪些问题、怎么安装,以及实际该怎么用。

这是什么

react-native-best-practices 是一份面向 AI 编程助手的 React Native 性能优化指南。出品方是 Callstack,托管在 GitHub 仓库 callstackincubator/agent-skills 下,许可证为 MIT。

它解决的不是「写一个新页面」,而是这类任务:

  • 界面卡顿、动画掉帧
  • JS 或原生内存持续上涨
  • 冷启动 TTI(Time to Interactive)过长
  • JS bundle 或安装包体积过大
  • 编写 / 审查 Turbo Module
  • 给现有 RN 代码做性能审查

Skill 的入口是 SKILL.md,详细步骤在 references/ 目录。当前 SKILL.md 列出 29 份专题文档,按前缀分成三类:

  • js-*:JavaScript / React 层(列表、重渲染、动画、内存)
  • native-*:iOS / Android 原生层(TTI、线程、Turbo Module、16KB 对齐)
  • bundle-*:打包与体积(barrel export、source-map-explorer、R8、Hermes mmap)

Callstack 在公告里把这三类最终映射到两个核心指标:FPSTTI。仓库 README 还把它归进插件包 Building React Native Apps,和导航、TV、库脚手架、升级这几项 Skill 一起安装。

核心功能

先测再改

SKILL.md 把优化流程写成固定循环:Measure → Optimize → Re-measure → Validate

  1. Measure:先记基线。运行时问题优先看 commit 时间线、重渲染次数、慢组件、最重的一次 commit,以及启动 / TTI;组件树深度或组件数量只作辅助,不能当成主证据。
  2. Optimize:按对应 reference 做针对性修改。
  3. Re-measure:用同一种测量方式再测一遍。
  4. Validate:确认指标真的变好。文档里用来说明验收方式的示例是:FPS 45→60、TTI 3.2s→1.8s、bundle 2.1MB→1.6MB。

如果指标没动,文档要求回滚,再试下一条建议。它还明确禁止:没有测到渲染或 FPS 问题,就不要推荐 memoization、原子状态或打开 React Compiler。

按优先级处理

优先级 类别 影响 文档前缀
1 FPS 与重渲染 CRITICAL js-*
2 包体积 CRITICAL bundle-*
3 TTI HIGH native-*bundle-*
4 原生性能 HIGH native-*
5 内存 MEDIUM-HIGH js-*native-*
6 动画 MEDIUM js-*

影响标签只是分诊顺序:CRITICAL 先处理,HIGH 其次,MEDIUM 在有证据时再做。

问题到文档的映射

SKILL.md 提供了一张问题对照表,助手应按表去读文件,而不是把 29 份文档一次塞进上下文:

问题 从哪份文档开始
整体卡顿 js-measure-fps.mdjs-profile-react.md
重渲染过多 js-profile-react.mdjs-react-compiler.md
启动慢 native-measure-tti.mdbundle-analyze-js.md
安装包过大 bundle-analyze-app.mdbundle-r8-android.md
内存上涨 js-memory-leaks.mdnative-memory-leaks.md
动画掉帧 js-animations-reanimated.md
列表滚动卡 js-lists-flatlist-flashlist.md
TextInput 延迟 js-uncontrolled-components.md
原生模块慢 native-turbo-modules.mdnative-threading-model.md
第三方库 16KB 对齐 native-android-16kb-alignment.md

安装与启用

官方 README 把通用安装方式指向 skills CLI,适用于 Claude Code、Cursor、GitHub Copilot、Gemini CLI、OpenCode 等兼容助手。只装这一份 Skill:

npx skills@latest add callstackincubator/agent-skills --skill react-native-best-practices

CLI 会询问目标助手和安装范围(项目级或用户级)。officialskills.sh 上的等价写法是把仓库 URL 写全:

npx skills add https://github.com/callstackincubator/agent-skills --skill react-native-best-practices

一次装仓库里全部 Callstack Skill,把 --skill 换成 '*' 即可。

各工具差异如下(以仓库当前文档为准):

OpenAI Codex:打开 Plugins,搜索 react native,安装需要的插件包。性能这份 Skill 在 Building React Native Apps 包里。

Claude Code:除了上面的 skills CLI,仓库还提供 marketplace。当前 .claude-plugin/marketplace.json(version 1.2.0)里的三个插件包是 building-react-native-appstesting-react-native-appsmigrating-to-react-native。性能相关 Skill 在第一个包中:

/plugin marketplace add callstackincubator/agent-skills
/plugin install building-react-native-apps@callstack-agent-skills

需要说明:Callstack 2026 年 1 月的公告曾写过单独安装 react-native-best-practices@callstack-agent-skills。当前 marketplace 已改成按场景打包,单独插件名不再出现在 marketplace.json 里,安装时以仓库现状为准。

Cursor:仓库提供 .cursor/rules/ 下的 .mdc 规则,可用 Cursor 的 Import rules from GitHub,指向 https://github.com/callstackincubator/agent-skills.git。需要完整正文时,把 skills/ 目录克隆或复制进工作区。也可以在对话里直接让助手读文件:

Read skills/react-native-best-practices/SKILL.md and help me optimize my FlatList performance

不支持 skills CLI 的助手,官方写了 AI Assistant Integration Guide,覆盖 Cursor、Copilot、Claude 项目知识库、ChatGPT Custom GPT、Windsurf 等手动挂载方式。

典型用法

装好之后,用自然语言描述任务即可。仓库 README 给的入口句是:

Review this React Native screen for performance problems.

更具体时,把代码和对应 reference 一起交给助手。下面三个例子都来自官方文档,可以按原样复现。

1. 列表卡顿:用虚拟列表替换 ScrollView

references/js-lists-flatlist-flashlist.md 把「长列表塞进 ScrollView」标成 CRITICAL。错误写法是一次挂载全部 item:

<ScrollView>
  {items.map((item) => <Item key={item.id} {...item} />)}
</ScrollView>

文档推荐的正确方向是 FlashList(或 FlatList / Legend List):

<FlashList
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <Item {...item} />}
  // FlashList v1 only: add estimatedItemSize.
  // FlashList v2+: do not add estimated sizing props.
/>

有两点审查约束,Skill 反复强调:

  • 先确认已安装的 FlashList 主版本。v1 需要 estimatedItemSize;v2 起该属性以及 estimatedListSizeestimatedFirstItemOffset 已废弃,不要再当成缺失项报出来。
  • 小而静态的内容继续用 ScrollView 即可,不要无测量就全盘替换。

在 Cursor 里可以这样点名文件:

@MyListComponent.tsx
@skills/react-native-best-practices/references/js-lists-flatlist-flashlist.md

Migrate this component to use FlashList

2. 先对运行时问题做 React 侧 profiling

FPS / 重渲染被标成第一优先级。推荐命令是 agent-device 驱动的 React DevTools:

agent-device react-devtools status
agent-device react-devtools wait --connected
agent-device react-devtools profile start
agent-device react-devtools profile stop
agent-device react-devtools profile slow --limit 5
agent-device react-devtools profile rerenders --limit 5
agent-device react-devtools profile timeline --limit 20

profile startprofile stop 之间,用常规 agent-device 操作把目标交互跑一遍。没有 agent-device 时,文档给了手工退路:Metro 按 j 或从 Dev Menu 打开 React Native DevTools,用 Profiler 录同一段交互。Release 包还要先接 @callstack/inspector,React DevTools 才能挂到 release 应用上。

测完之后,常见修复也写在 Quick Reference 里,但都带前提:

  • 长列表:ScrollView 换成 FlatList / FlashList / Legend List
  • profiling 显示级联重渲染:再考虑 React Compiler
  • profiling 显示 store / context 大范围更新:再考虑 Jotai / Zustand 这类原子状态
  • 昂贵计算:useDeferredValue

没有 profiling 证据,不要改 useMemo / useCallback 依赖,也不要凭猜测报 stale closure。

3. 分析 JS bundle,再决定砍体积

包体积同样是 CRITICAL。先打一份 minify 后的 bundle,再用 source-map-explorer 看依赖占比:

npx react-native bundle \
  --entry-file index.js \
  --bundle-output output.js \
  --platform ios \
  --sourcemap-output output.js.map \
  --dev false --minify true

npx source-map-explorer output.js --no-border-checks

改完用同样命令再打一份,对比 ls -lh output.js。文档里的示例数字是 2.1 MB 降到 1.6 MB。常见手段包括:不要走 barrel import、确认 Hermes 已覆盖后再删 Intl polyfill、评估 tree shaking(Expo SDK 52+ 的实验性无用导入删除,或项目里已经在用的 Re.Pack)、Android 打开 R8。

Android R8 的最小配置在 references/bundle-r8-android.md

// android/app/build.gradle
android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true  // Requires minifyEnabled
        }
    }
}

文档提醒:标准 RN 模板默认不开启 R8;shrinkResources 依赖 minifyEnabled。反射或代码生成较多的库(例如 Firebase)可能要补 keep 规则,改完必须用 release 包做回归。参考文档给的体积示例是 9.5 MB 降到 6.3 MB,大约 33%;它同时写明更大的应用常见降幅大约 20%–30%。这是指南里的示例,不是你当前工程的保证值。

TTI 侧,文档要求只用冷启动数据(排除 warm / hot / prewarm),用 react-native-performance 打点。常见修复包括:RN 0.78 及更早版本关闭 Android JS bundle 压缩以便 Hermes mmap、使用 react-native-screens 做原生导航、对常用的重页面做预加载。

适用场景与注意事项

适合这些人和场景:

  • 维护 React Native 或 Expo 应用,正在查卡顿、启动慢、包体积或内存问题
  • 用 AI 助手做 RN 代码审查,希望它按 Callstack 的分诊顺序给建议,而不是先堆 memo
  • 写 Turbo Module,需要异步接口和后台线程方面的约束
  • 要过 Google Play 的 16KB 页面对齐,需要核对第三方 so 库

使用时注意下面几条,都来自官方文档,不是额外发挥:

  1. 这不是自动改包工具。 它提供决策、配置和可复现的测量命令。Callstack 公告也写了:火焰图、内存时间线这类视觉工具,Agent 目前仍不容易直接解读,项目近期重点仍是能被精确描述并稳定套用的实践。
  2. 先读 SKILL.md,再按需打开单份 reference。 29 份文档一次全读既浪费上下文,也容易把 MEDIUM 项提前做完。
  3. 库版本必须先核对。 FlashList v1 / v2 对 estimatedItemSize 的要求相反;API 相关修复不能脱离当前依赖版本。
  4. 命令按本地开发操作对待。 SKILL.md 的 Security Notes 要求:跑 shell 前先审一遍,优先固定版本的工具,不要把远端脚本直接 pipe 进 shell;第三方库仍按正常供应链管理;远程分片加载只接受本方可控、与当前发版绑定的产物。
  5. Release 和 Debug 行为可能不同。 公告把「release 和 debug 表现不一致」列为常见问题;R8、Hermes mmap、资源压缩都要在 release 包上验证。
  6. 可与 agent-device 搭配。 集成指南写明:需要真机 / 模拟器走流程、截图、打点时,先看环境里是否已有 agent-device Skill;没有且确实需要设备验证时,再按环境允许的方式安装,否则退回项目原有的手工验证路径。

小结

react-native-best-practices 把 Callstack 多年 RN 性能工作收成 Agent 可检索的手册:先测后改,按 FPS、包体积、TTI、原生、内存、动画的顺序处理,并用 js-* / native-* / bundle-* 把问题映射到具体文档。对正在用 AI 助手维护 React Native 应用的人来说,它主要解决的是「建议很热闹、指标没变化」。

官方地址:

  • Skill 目录:https://github.com/callstackincubator/agent-skills/tree/main/skills/react-native-best-practices
  • 仓库说明与安装:https://github.com/callstackincubator/agent-skills
  • 公告:https://www.callstack.com/blog/announcing-react-native-best-practices-for-ai-agents
  • 电子书原文:https://www.callstack.com/ebooks/the-ultimate-guide-to-react-native-optimization
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜