关于 react-native-specialist
面向 React Native 开发者的技能,涵盖新架构、原生模块和 Expo 工作流。内容包括架构选择、原生集成、性能实践与故障排查。
主要功能
- 01新架构指导
- 02TurboModules 与 Fabric 工作流
- 03Expo 和 EAS 配置指导
- 04原生崩溃与桥接调试
- 05性能和架构检查清单
适用场景
- 01将应用从旧版 Bridge 迁移
- 02构建自定义原生模块
- 03配置 Expo 构建和更新工作流
- 04排查渲染或内存问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ 404kidwiz/ claude-supercode-skills --skill react-native-specialist安装后在 Claude Code 中输入/react-native-specialist确认已加载。
详细介绍
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%
- Bundle 体积缩小 30%
- 改善了原生边界之间的类型安全
- 崩溃报告和调试效果更佳
示例 2:自定义原生模块
场景: 需要为健身应用集成低功耗蓝牙。
实现:
- 创建 TypeScript 原生模块接口
- 实现原生代码(iOS 使用 Swift,Android 使用 Kotlin)
- 暴露 RNTurboModule,以便跨平台访问
- 添加适当的内存管理和生命周期处理
- 实现全面的错误处理
结果:
- BLE 操作在两个平台上都能无缝运行
- 类型安全的桥接可防止运行时错误
- 代码量比传统原生模块减少 50%
- 可随 RN 升级持续维护
示例 3:性能优化
场景: 应用出现滚动卡顿和内存问题。
实现:
- 启用 Hermes 引擎
- 将 FlatList 替换为 FlashList
- 实现记忆化(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:所有代码均使用 TypeScript
2. 决策框架
架构选择
Which architecture to use?
│
├─ **New Architecture (Default for 0.76+)**
│ ├─ **TurboModules:** Lazy-loaded native modules (Sync/Async).
│ ├─ **Fabric:** C++ Shadow Tree for UI (No bridge serialization).
│ ├─ **Codegen:** Type-safe spec for Native <-> JS communication.
│ └─ **Bridgeless Mode:** Removes the legacy bridge entirely.
│
└─ **Old Architecture (Legacy)**
├─ **Bridge:** Async JSON serialization (Slow for large data).
└─ **Maintenance:** Only for unmigrated legacy libraries.
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 线程上实现 60 fps 的拖动手势。
步骤:
-
设置
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:“跨越 Bridge”的动画
表现形式:
- 使用
Animated.timing并设置useNativeDriver: false。 - 在
useEffect中计算布局并调用setState。
失败原因:
- 在 JS 线程上运行。如果 JS 正忙(例如正在获取数据),就会丢帧。
正确做法:
- 使用 Reanimated 或
useNativeDriver: true。
❌ 反模式 2:未使用 Hermes 的大型 Bundle
表现形式:
- 在 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 包和压缩
- 手动链接: 在无需手动链接时仍手动链接原生模块——使用自动链接
测试反模式
- 没有端到端测试: 只有单元测试——添加 Maestro 或 Detox 测试
- 平台条件判断: 平台检查过多——抽象平台差异
- 硬编码尺寸: 使用固定像素值——采用相对尺寸
- 缺少 testID: 没有无障碍标识符——添加 testID 以便测试
评论
支持 Markdown