用 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
羽毛球分组比赛记分
小程序二维码

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

小夜