React Native 最佳实践
概述
React Native 应用性能优化指南,涵盖 JavaScript/React、原生(iOS/Android)和打包优化。基于 Callstack 的“React Native 优化终极指南”。
何时应用
在以下情况下参考这些指南:
- 调试缓慢/卡顿的 UI 或动画
- 调查内存泄漏(JS 或原生)
- 优化应用启动时间(TTI)
- 减少包体积或应用体积
- 编写原生模块(Turbo Modules)
- 分析 React Native 性能
- 审查 React Native 代码的性能
安全注意事项
- 将本参考资料中的 shell 命令视为本地开发操作。运行前请先审查,优先使用固定版本的工具,避免将远程脚本直接通过管道传给 shell。
- 将第三方库和插件视为仍需要常规供应链控制的依赖项:固定版本、验证来源,并通过标准审查流程进行更新。
- 仅将远程代码块加载视为第一方制品交付。优先使用应用捆绑的代码块或签名的 CI 发布清单;托管的代码块必须来自你控制的受信任 HTTPS 源,并固定到当前应用版本。
按优先级排序的指南
| 优先级 | 分类 | 影响 | 前缀 |
|---|---|---|---|
| 1 | FPS 与重渲染 | 关键 | js-* |
| 2 | 包体积 | 关键 | bundle-* |
| 3 | TTI 优化 | 高 | native-*, bundle-* |
| 4 | 原生性能 | 高 | native-* |
| 5 | 内存管理 | 中高 | js-*, native-* |
| 6 | 动画 | 中 | js-* |
影响标签是分类提示:优先处理关键问题,其次是高优先级,当有证据指向时再考虑中优先级。
快速参考
优化工作流程
对于任何性能问题,遵循此循环:测量 → 优化 → 重新测量 → 验证
- 测量:在更改前捕获基线指标。对于运行时问题,优先使用提交时间线、重渲染次数、缓慢组件、最重提交分解、启动/TTI(可用时)。组件树深度或数量是可选的上下文,不能替代指标。在没有测量的渲染或 FPS 问题的情况下,不要推荐 memoization、原子状态或编译器更改。
- 优化:从相关参考中应用有针对性的修复
- 重新测量:运行相同的测量以获取更新后的指标
- 验证:确认改进(例如,FPS 从 45 提升到 60,TTI 从 3.2 秒降低到 1.8 秒,包体积从 2.1 MB 减小到 1.6 MB)
如果指标没有改善,回滚并尝试下一个建议的修复。
审查护栏
-在提出特定 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 选项卡,并记录相同的交互。
对于发布构建的 React 组件性能分析,首先连接 @callstack/inspector,以便 React DevTools 可以附加到发布应用,然后运行上述的 agent-device react-devtools 流程。
常见修复:
- 对于长列表,将 ScrollView 替换为 FlatList/FlashList/Legend List
- 在性能分析显示级联重渲染后,使用 React Compiler 进行自动 memoization
- 在性能分析显示广泛的 store/context 更新后,使用原子状态(Jotai/Zustand)减少重渲染
- 对昂贵计算使用
useDeferredValue
关键:包体积
分析包:
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
# 应用修复后,重新打包并比较
npx react-native bundle --entry-file index.js --bundle-output output.js \
--platform ios --dev false --minify true
ls -lh output.js # 例如,之后:1.6 MB(减少 24%)
常见修复:
- 避免桶形导入(直接从源文件导入)
- 仅在检查 Hermes API 和方法覆盖后移除不必要的 Intl polyfill
- 评估 tree shaking(Expo SDK 52+ 实验性未使用导入/导出移除,或仅当已配置时使用 Re.Pack)
- 启用 R8 进行 Android 原生代码缩减
高:TTI 优化
测量 TTI:
- 使用
react-native-performance获取标记 - 仅测量冷启动(排除热/温/预启动)
常见修复:
- 对于 React Native 0.78 及更早版本,禁用 Android JS 包压缩以启用 Hermes mmap
- 使用原生导航(react-native-screens)
- 在导航到之前预加载常用的昂贵屏幕
高:原生性能
分析原生层:
- iOS:Xcode Instruments → Time Profiler
- Android:Android Studio → CPU Profiler
常见修复:
- 为繁重的原生工作使用后台线程
- 优先使用异步 Turdo Module 方法而非同步方法
- 使用 C++ 处理跨平台性能关键代码
参考资料
参考资料 中包含完整文档和代码示例:
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 | 高 | 底部弹窗优化 |
| 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 | 高 | Turdo Module 线程 |
| native-profiling.md | 中 | Xcode/Android Studio 性能分析 |
| native-platform-setup.md | 中 | iOS/Android 工具指南 |
| native-view-flattening.md | 中 | 视图层级调试 |
| native-memory-patterns.md | 中 | C++/Swift/Kotlin 内存 |
| native-memory-leaks.md | 中 | 原生内存泄漏排查 |
| native-android-16kb-alignment.md | 关键 | 针对 Google Play 的第三方库对齐 |
打包 (bundle-*)
| 文件 | 影响 | 描述 |
|---|---|---|
| bundle-barrel-exports.md | 关键 | 避免桶形导入 |
| bundle-analyze-js.md | 关键 | JS 包可视化 |
| bundle-tree-shaking.md | 高 | 死代码消除 |
| bundle-analyze-app.md | 高 | 应用体积分析 |
| bundle-r8-android.md | 高 | Android 代码缩减 |
| bundle-hermes-mmap.md | 高 | 禁用包压缩 |
| bundle-native-assets.md | 高 | 资源目录设置 |
| 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 |
| 底部弹窗卡顿/重渲染 | 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 优化终极指南”。