React Native 最佳實踐
總覽
React Native 應用程式效能優化指南,涵蓋 JavaScript/React、原生 (iOS/Android) 與打包優化。基於 Callstack 的「React Native 優化終極指南」。
何時套用
在以下情況參考這些指南:
- 除錯緩慢/卡頓的 UI 或動畫
- 調查記憶體洩漏 (JS 或原生)
- 優化應用程式啟動時間 (TTI)
- 減少 Bundle 或應用程式大小
- 編寫原生模組 (Turbo Modules)
- 分析 React Native 效能
- 審查 React Native 程式碼的效能
安全注意事項
- 將這些參考資料中的 Shell 指令視為本地開發者操作。執行前請務必審查,優先使用固定版本的工具,並避免將遠端腳本直接 Pipe 到 Shell。
- 將第三方函式庫與外掛視為仍需一般供應鏈控制的相依性:鎖定版本、驗證來源,並透過標準審查流程進行更新。
- 將遠端區塊載入僅視為第一方成品傳遞。優先使用應用程式內建的區塊或已簽署的 CI 發布清單;託管的區塊必須來自您控制的、受信任的 HTTPS 來源,並鎖定在當前應用程式版本。
按優先順序的指南
| 優先級 | 類別 | 影響 | 前綴 |
|---|---|---|---|
| 1 | FPS 與重新渲染 | 關鍵 | js-* |
| 2 | Bundle 大小 | 關鍵 | bundle-* |
| 3 | TTI 優化 | 高 | native-*, bundle-* |
| 4 | 原生效能 | 高 | native-* |
| 5 | 記憶體管理 | 中高 | js-*, native-* |
| 6 | 動畫 | 中等 | js-* |
影響標籤是分流提示:先處理「關鍵」,其次是「高」,最後是「中等」(當證據指向該處時)。
快速參考
優化工作流程
對於任何效能問題,請遵循這個循環:測量 → 優化 → 再測量 → 驗證
- 測量:在變更前捕獲基準指標。對於執行時期問題,優先使用提交時間軸、重新渲染次數、最慢元件、最重提交的分解,以及啟動/TTI(如果可用)。元件樹深度或元件數量是可有可無的背景資訊,不能作為替代。在沒有測量到渲染或 FPS 問題的情況下,請不要建議使用 memoization、原子狀態或編譯器變更。
- 優化:套用來自相關參考資料的目標修復
- 再測量:執行相同的測量以獲取更新後的指標
- 驗證:確認改善(例如:FPS 45→60,TTI 3.2秒→1.8秒,Bundle 2.1MB→1.6MB)
如果指標沒有改善,請還原並嘗試下一個建議的修復。
審查護欄
- 在建議特定 API 的修復前,請檢查函式庫版本。例如:FlashList v2 已棄用
estimatedItemSize,因此不要將其標記為遺漏。 - 除非
useMemo或useCallback的行為明顯錯誤,或分析顯示浪費的工作與該值相關,否則不要建議更改其相依性。 - 不要推測性地報告陳舊閉包。在指出問題前,請顯示陳舊的讀取路徑、重現步驟或分析器證據。
- 在分析流程時,請測量目標互動本身。不要將元件樹深度或元件數量視為主要的效能證據。
關鍵:FPS 與重新渲染
先進行分析:
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) 或開發選單中開啟 React Native DevTools,使用分析器 (Profiler) 標籤頁,並記錄相同的互動。
對於 Release Build 的 React 元件分析,請先連線 @callstack/inspector,以便 React DevTools 可以附加到 Release 應用程式,然後執行上述的 agent-device react-devtools 流程。
常見修復:
- 對於長列表,將 ScrollView 替換為 FlatList/FlashList/Legend List
- 在分析顯示級聯重新渲染後,使用 React Compiler 進行自動 memoization
- 在分析顯示廣泛的 Store/Context 更新後,使用原子狀態 (Jotai/Zustand) 來減少重新渲染
- 對於昂貴的計算,使用
useDeferredValue
關鍵:Bundle 大小
分析 Bundle:
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 # 例如:Before: 2.1 MB
# 套用修復後,重新打包並比較
npx react-native bundle --entry-file index.js --bundle-output output.js \
--platform ios --dev false --minify true
ls -lh output.js # 例如:After: 1.6 MB (減少 24%)
常見修復:
- 避免 Barrel Imports(直接從來源匯入)
- 僅在檢查 Hermes API 和方法覆蓋率後,才移除不必要的 Intl Polyfill
- 評估 Tree Shaking(Expo SDK 52+ 實驗性的未使用 Import/Export 移除,或僅在已配置時使用 Re.Pack)
- 啟用 R8 以進行 Android 原生程式碼縮減
高:TTI 優化
測量 TTI:
- 使用
react-native-performance作為標記 - 僅測量冷啟動(排除熱/暖/預熱啟動)
常見修復:
- 對於 React Native 0.78 及更早版本,停用 Android JS Bundle 壓縮以啟用 Hermes mmap
- 使用原生導航 (react-native-screens)
- 在導航到常用且昂貴的畫面之前,預先載入它們
高:原生效能
分析原生:
- iOS:Xcode Instruments → Time Profiler
- Android:Android Studio → CPU Profiler
常見修復:
- 對繁重的原生工作使用背景執行緒
- 偏好使用非同步而非同步的 Turbo Module 方法
- 對於跨平台效能關鍵程式碼,使用 C++
參考資料
完整文件與程式碼範例位於 references/:
JavaScript/React (js-*)
| 檔案 | 影響 | 描述 |
|---|---|---|
| js-lists-flatlist-flashlist.md | 關鍵 | 用虛擬化列表取代 ScrollView |
| js-profile-react.md | 中等 | 使用 agent-device react-devtools 進行分析 |
| js-measure-fps.md | 高 | FPS 監控與測量 |
| js-memory-leaks.md | 中等 | JS 記憶體洩漏偵測 |
| js-atomic-state.md | 高 | Jotai/Zustand 模式 |
| js-concurrent-react.md | 高 | useDeferredValue, useTransition |
| js-react-compiler.md | 高 | 自動 Memoization |
| js-animations-reanimated.md | 中等 | Reanimated Worklets |
| js-bottomsheet.md | 高 | Bottom Sheet 優化 |
| js-uncontrolled-components.md | 高 | TextInput 優化 |
原生 (native-*)
| 檔案 | 影響 | 描述 |
|---|---|---|
| native-turbo-modules.md | 高 | 建立快速的原生模組 |
| native-sdks-over-polyfills.md | 高 | 原生 vs JS 函式庫 |
| native-measure-tti.md | 高 | TTI 測量設定 |
| native-threading-model.md | 高 | Turbo Module 執行緒 |
| native-profiling.md | 中等 | Xcode/Android Studio 分析 |
| native-platform-setup.md | 中等 | iOS/Android 工具指南 |
| native-view-flattening.md | 中等 | View 階層除錯 |
| native-memory-patterns.md | 中等 | C++/Swift/Kotlin 記憶體 |
| native-memory-leaks.md | 中等 | 原生記憶體洩漏偵測 |
| native-android-16kb-alignment.md | 關鍵 | 為 Google Play 進行第三方函式庫對齊 |
打包 (bundle-*)
| 檔案 | 影響 | 描述 |
|---|---|---|
| bundle-barrel-exports.md | 關鍵 | 避免 Barrel Imports |
| bundle-analyze-js.md | 關鍵 | JS Bundle 視覺化 |
| bundle-tree-shaking.md | 高 | 死碼消除 |
| bundle-analyze-app.md | 高 | 應用程式大小分析 |
| bundle-r8-android.md | 高 | Android 程式碼縮減 |
| bundle-hermes-mmap.md | 高 | 停用 Bundle 壓縮 |
| bundle-native-assets.md | 高 | Asset 目錄設定 |
| bundle-library-size.md | 中等 | 評估相依性 |
| bundle-code-splitting.md | 中等 | 遠端區塊載入保護措施 |
問題 → 技能對應
| 問題 | 從此開始 |
|---|---|
| 應用程式感覺緩慢/卡頓 | js-measure-fps.md → js-profile-react.md |
| 過多重新渲染 | js-profile-react.md → js-react-compiler.md |
| 啟動緩慢 (TTI) | 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 |
| Bottom Sheet 卡頓/重新渲染 | js-bottomsheet.md → js-animations-reanimated.md |
| 列表滾動卡頓 | js-lists-flatlist-flashlist.md |
| TextInput 延遲 | js-uncontrolled-components.md |
| 原生模組緩慢 | native-turbo-modules.md → native-threading-model.md |
| 原生函式庫對齊問題 | native-android-16kb-alignment.md |
出處
基於 Callstack 的「React Native 優化終極指南」。