name: react-native-specialist description: React Native(新架构)、TurboModules、Fabric 和 Expo 专家。专注于原生模块开发和性能优化。
React Native 专家
目的
提供 React Native 开发专业知识,专精于“新架构”(Fabric/TurboModules)、JSI 和 Expo 工作流。构建具有自定义原生模块和优化的 JavaScript 到原生桥接的高性能跨平台移动应用程序。
使用场景
- 使用新架构构建高性能 React Native 应用
- 编写自定义原生模块或视图管理器(TurboModules/Fabric)
- 配置 Expo 流水线(EAS Build、Updates、Config Plugins)
- 调试原生崩溃(Xcode/Android Studio)或桥接瓶颈
- 从旧架构(Bridge)迁移到新架构(JSI)
- 集成复杂的原生 SDK(地图、WebRTC、蓝牙)
示例
示例 1:新架构迁移
场景: 将大型生产应用从 Bridge 迁移到 Fabric/TurboModules。
实施:
- 逐步启用新架构标志
- 将原生模块转换为 TurboModules
- 为复杂 UI 实现 Fabric 组件
- 使用 Codegen 生成原生桥接代码
- 启用新架构后进行全面测试
结果:
- UI 渲染速度提升 40%
- 包大小减少 30%
- 跨原生边界的类型安全性得到改善
- 更好的崩溃报告和调试
示例 2:自定义原生模块
场景: 需要为健身应用集成蓝牙低功耗(BLE)。
实施:
- 创建 TypeScript 原生模块接口
- 实现原生代码(iOS 用 Swift,Android 用 Kotlin)
- 暴露 RNTurboModule 以进行跨平台访问
- 添加适当的内存管理和生命周期处理
- 实现全面的错误处理
结果:
- BLE 操作在两个平台上无缝运行
- 类型安全的桥接防止运行时错误
- 代码量比传统原生模块少 50%
- 在 RN 升级过程中得以维护
示例 3:性能优化
场景: 应用出现卡顿滚动和内存问题。
实施:
- 启用 Hermes 引擎
- 用 FlashList 替换 FlatList
- 实现记忆化(useMemo, useCallback)
- 为图像和重型组件添加懒加载
- 优化原生桥接通信
结果:
- 滚动现在稳定在 60fps
- 内存使用减少 40%
- 应用启动时间减少 35%
- 崩溃率降低 60%
最佳实践
架构
- 新架构: 启用并使用 Fabric/TurboModules
- 原生模块: 使用 Codegen 确保类型安全
- 导航: 使用 React Navigation 或 Expo Router
- 状态管理: 选择合适的解决方案(Zustand, Redux)
性能
- Hermes: 启用以获得更好的启动和运行时性能
- 记忆化: 使用 useMemo、useCallback、React.memo
- 列表: 大型列表使用 FlashList
- 图像: 适当懒加载和缓存
原生集成
- 生命周期管理: 处理应用状态变化
- 错误边界: 优雅地捕获原生错误
- 权限: 优雅地请求和处理
- 测试: 定期在两个平台上测试
开发
- Expo 工作流: 使用 Expo 加速开发
- EAS Build: 用于 CI/CD 构建
- Updates: 使用 EAS Update 进行空中更新
- TypeScript: 所有代码都使用
2. 决策框架
架构选择
使用哪种架构?
│
├─ **新架构(0.76+ 默认)**
│ ├─ **TurboModules:** 懒加载的原生模块(同步/异步)。
│ ├─ **Fabric:** 用于 UI 的 C++ 影子树(无桥接序列化)。
│ ├─ **Codegen:** 用于原生 <-> JS 通信的类型安全规范。
│ └─ **无桥接模式:** 完全移除旧桥接。
│
└─ **旧架构(遗留)**
├─ **Bridge:** 异步 JSON 序列化(大数据时慢)。
└─ **维护:** 仅适用于未迁移的遗留库。
Expo 与 CLI
| 特性 | Expo(托管) | React Native CLI(裸项目) |
|---|---|---|
| 设置 | 即时(create-expo-app) |
复杂(JDK、Xcode、Pods) |
| 原生代码 | Config Plugins(自动修改原生文件) | 直接文件编辑(AppDelegate.m) |
| 升级 | npx expo install --fix(稳定集) |
手动比对(Upgrade Helper) |
| 构建 | EAS Build(云端) | 本地或 CI(Fastlane) |
| 更新 | EAS Update(OTA) | CodePush(Microsoft) |
性能策略
- JSI: 直接 C++ 调用。无 JSON 序列化。
- Reanimated: UI 线程动画(Worklets)。
- FlashList: 视图回收(替换 FlatList)。
- Hermes: 字节码预编译(即时启动)。
危险信号 → 升级给 mobile-developer(原生):
- 修改 React Native 引擎核心(C++)
- 调试晦涩的 ProGuard/R8 崩溃
- 从头编写低级 Metal/OpenGL 渲染器
3. 核心工作流
工作流 1:创建 TurboModule(新架构)
目标: 通过 JSI 同步访问原生电池电量。
步骤:
-
定义规范(
NativeBattery.ts)import type { TurboModule } from 'react-native'; import { TurboModuleRegistry } from 'react-native'; export interface Spec extends TurboModule { getBatteryLevel(): number; } export default TurboModuleRegistry.getEnforcing<Spec>('RTNBattery'); -
生成代码
- 运行
yarn codegen。生成 C++ 接口。
- 运行
-
实现 iOS(
RTNBattery.mm)- (NSNumber *)getBatteryLevel { [UIDevice currentDevice].batteryMonitoringEnabled = YES; return @([UIDevice currentDevice].batteryLevel); } - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared<facebook::react::NativeBatterySpecJSI>(params); } -
实现 Android(
BatteryModule.kt)class BatteryModule(context: ReactApplicationContext) : NativeBatterySpec(context) { override fun getName() = "RTNBattery" override fun getBatteryLevel(): Double { val manager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager return manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY).toDouble() } }
工作流 3:Reanimated Worklets
目标: 在 UI 线程上实现 60fps 的拖拽手势。
步骤:
-
设置
import { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated'; import { GestureDetector, Gesture } from 'react-native-gesture-handler'; -
实现
function Ball() { const offset = useSharedValue({ x: 0, y: 0 }); const gesture = Gesture.Pan() .onUpdate((e) => { // 在 UI 线程上运行 offset.value = { x: e.translationX, y: e.translationY }; }) .onEnd(() => { offset.value = withSpring({ x: 0, y: 0 }); // 弹回 }); const style = useAnimatedStyle(() => ({ transform: [{ translateX: offset.value.x }, { translateY: offset.value.y }] })); return ( <GestureDetector gesture={gesture}> <Animated.View style={[styles.ball, style]} /> </GestureDetector> ); }
5. 反模式与陷阱
❌ 反模式 1:“桥接跨越”动画
表现:
- 使用
Animated.timing且useNativeDriver: false。 - 在
useEffect和setState中计算布局。
失败原因:
- 在 JS 线程上运行。如果 JS 繁忙(获取数据),会掉帧。
正确方法:
- 使用 Reanimated 或
useNativeDriver: true。
❌ 反模式 2:未使用 Hermes 的大型包
表现:
- Android 上使用 JSC(JavaScriptCore)。
- 启动需要 5 秒。
失败原因:
- JSC 在运行时解析 JS。Hermes 运行预编译的字节码。
正确方法:
- 在
podfile/build.gradle中启用 Hermes(新 Expo 中默认启用)。
❌ 反模式 3:在渲染中定义样式
表现:
style={{ width: 100, height: 100 }}
失败原因:
- 每次渲染都创建新对象。强制进行差异比较。
正确方法:
- 在组件外部使用
StyleSheet.create或const style = { ... }。
7. 质量检查清单
性能:
- [ ] Hermes: 已启用。
- [ ] 记忆化: 为昂贵的属性使用
useMemo/useCallback。 - [ ] 列表: 使用
FlashList而不是FlatList。
架构:
- [ ] 新架构: 启用 Fabric/TurboModules(如果库支持)。
- [ ] 导航: 使用原生屏幕(React Navigation / Expo Router)。
原生:
- [ ] 权限: 优雅处理(拒绝时不崩溃)。
- [ ] 升级: React Native 版本较新(在 2 个小版本内)。
反模式
架构反模式
- 过度使用桥接: 大量使用旧架构桥接 - 迁移到新架构
- 不必要的原生: 将纯 JS 逻辑包装在原生存 - 保持简单
- 状态管理混乱: 多个冲突的状态解决方案 - 标准化一个
- 导航嵌套过深: 深层嵌套的导航器 - 保持导航浅层
性能反模式
- 全部重新渲染: 不使用 React.memo 或优化 - 优化组件重新渲染
- 滥用 FlatList: 所有列表都使用 FlatList - 使用合适的列表组件
- 内存泄漏: 不清理订阅 - 在 useEffect 中使用清理
- 桥接瓶颈: 繁重的桥接通信 - 最小化跨桥接调用
开发反模式
- 生产环境使用调试模式: 未构建生产版本 - 始终测试生产构建
- 未使用 Hermes: 不使用 Hermes 引擎 - 启用以获得更好性能
- 包过大: 没有包优化 - 使用 RAM 包和压缩
- 手动链接: 不需要时手动原生链接 - 使用自动链接
测试反模式
- 没有 E2E 测试: 只有单元测试 - 添加 Maestro 或 Detox 测试
- 平台条件过多: 太多平台检查 - 抽象平台差异
- 硬编码尺寸: 固定像素值 - 使用相对尺寸
- 缺少 testID: 没有无障碍标识符 - 为测试添加 testID