前言¶
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 在公告里把这三类最终映射到两个核心指标:FPS 和 TTI。仓库 README 还把它归进插件包 Building React Native Apps,和导航、TV、库脚手架、升级这几项 Skill 一起安装。
核心功能¶
先测再改¶
SKILL.md 把优化流程写成固定循环:Measure → Optimize → Re-measure → Validate。
- Measure:先记基线。运行时问题优先看 commit 时间线、重渲染次数、慢组件、最重的一次 commit,以及启动 / TTI;组件树深度或组件数量只作辅助,不能当成主证据。
- Optimize:按对应 reference 做针对性修改。
- Re-measure:用同一种测量方式再测一遍。
- 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.md → js-profile-react.md |
| 重渲染过多 | js-profile-react.md → js-react-compiler.md |
| 启动慢 | native-measure-tti.md → bundle-analyze-js.md |
| 安装包过大 | bundle-analyze-app.md → bundle-r8-android.md |
| 内存上涨 | js-memory-leaks.md 或 native-memory-leaks.md |
| 动画掉帧 | js-animations-reanimated.md |
| 列表滚动卡 | js-lists-flatlist-flashlist.md |
| TextInput 延迟 | js-uncontrolled-components.md |
| 原生模块慢 | native-turbo-modules.md → native-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-apps、testing-react-native-apps、migrating-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 起该属性以及estimatedListSize、estimatedFirstItemOffset已废弃,不要再当成缺失项报出来。 - 小而静态的内容继续用 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 start 和 profile 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 库
使用时注意下面几条,都来自官方文档,不是额外发挥:
- 这不是自动改包工具。 它提供决策、配置和可复现的测量命令。Callstack 公告也写了:火焰图、内存时间线这类视觉工具,Agent 目前仍不容易直接解读,项目近期重点仍是能被精确描述并稳定套用的实践。
- 先读
SKILL.md,再按需打开单份 reference。 29 份文档一次全读既浪费上下文,也容易把 MEDIUM 项提前做完。 - 库版本必须先核对。 FlashList v1 / v2 对
estimatedItemSize的要求相反;API 相关修复不能脱离当前依赖版本。 - 命令按本地开发操作对待。
SKILL.md的 Security Notes 要求:跑 shell 前先审一遍,优先固定版本的工具,不要把远端脚本直接 pipe 进 shell;第三方库仍按正常供应链管理;远程分片加载只接受本方可控、与当前发版绑定的产物。 - Release 和 Debug 行为可能不同。 公告把「release 和 debug 表现不一致」列为常见问题;R8、Hermes mmap、资源压缩都要在 release 包上验证。
- 可与
agent-device搭配。 集成指南写明:需要真机 / 模拟器走流程、截图、打点时,先看环境里是否已有agent-deviceSkill;没有且确实需要设备验证时,再按环境允许的方式安装,否则退回项目原有的手工验证路径。
小结¶
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