前言¶
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