高频思考题与答题框架
1. React Native 新架构到底“新”在哪?
答题要点:
- 渲染:Fabric(C++ renderer + 新的 UI 管线)
- 模块:TurboModules(更明确的接口与调用链)
- 运行:Bridgeless(弱化/替代传统 bridge 依赖)
- 调度:RuntimeScheduler + 更明确事件循环语义
2. 为什么 RN 要强推新架构默认化?
答题要点:
- 降低组合复杂度(避免“半新架构”)
- 让生态库对齐统一目标
- 用 interop + feature flags 缓冲迁移
可引用:DefaultNewArchitectureEntryPoint.kt 的校验与 deprecated 重载。
3. RN 如何做 Android 与 iOS 的编译兼容?
答题要点:
- Android:Gradle 插件注入 codegen/autolinking/hermes 任务
- iOS:Pods + Xcode 脚本 + post_install 改写编译配置
- C++:自动生成 CMake/注册代码连接三方库
4. Codegen 在 RN 的意义是什么?
答题要点:
- 解决跨语言接口一致性问题
- 减少手写 glue code 与注册样板
- 把生态库接入标准化(声明配置 -> 自动产物)
5. Autolinking 和 Codegen 的关系?
答题要点:
- Autolinking 负责“发现与接入依赖”
- Codegen 负责“生成类型安全/平台所需代码”
- 两者在 preBuild 前被串联,保证编译图完整
6. Hermes 默认化背后的工程价值?
答题要点:
- 不仅是性能,更是工具链统一
- bundle/bytecode/sourcemap/debug 流程一致
- 降低多引擎分叉维护成本
7. 你如何评价 RN 的工程化成熟度?
答题结构(推荐):
- Monorepo 与多包治理
- 跨语言构建编排(Gradle/Pods/C++/JS)
- 代码生成与自动接入机制
- 测试与发布流水线
- 生态迁移治理(issue/PR 驱动)
8. 如果你在业务中落地类似体系,会先做什么?
参考回答:
- 先统一 build pipeline 与产物规范
- 再把跨语言接口收敛为 schema + codegen
- 最后把手工接线(autolinking 类问题)插件化
9. 如何回答“新架构有哪些坑”?
建议诚实表达三类风险:
- 生态库兼容滞后(如 Fabric API 变更)
- 构建脚本/工具链门槛变高
- 调度语义变化引发历史时序依赖问题
然后补一句:RN 官方通常通过 RFC、feature flags、兼容回填 PR 来降低迁移摩擦。
10. 一段 40 秒电梯演讲式总结
“我理解的 React Native 已经不是简单的 JS 桥接框架,而是 New Architecture 驱动的跨语言运行时工程。它通过 Fabric/TurboModules/Bridgeless 统一架构方向,用 RuntimeScheduler 明确事件循环语义,再通过 Gradle 插件、Pods 脚本、Codegen 和 Autolinking 把多平台构建工程化。Hermes 默认化与预编译体系则保证了性能和交付效率。我的学习重点不是 API 记忆,而是理解这些设计为什么能在大规模生态下持续演进。”
11. 直接使用 React Native Core 时,有哪些最佳实践和错误用例对照?
结论表述(先说结论)
- 最佳实践是:遵循官方默认工程链路(New Architecture 默认、Hermes 默认、框架命令驱动 iOS 依赖准备),尽量少做“逆默认”的手工流程。
- 常见错误是:手工绕开工具链 或 在新架构下沿用旧心智,导致构建失败、崩溃或行为误判。
最佳实践 vs 错误用例(可直接背)
- iOS 依赖安装方式
- 最佳实践:优先用
yarn ios/npx expo run:ios这类框架命令,由其统一处理 CocoaPods/SPM 过渡。 - 错误用例:长期直接
pod install作为唯一入口。 - 依据:
react_native_pods.rb已有 deprecation 提示;社区讨论也明确“推荐使用框架命令而非直接 pod install”(discussion #924)。
- 架构开关认知
- 最佳实践:按“新架构是主路径”来配置和排查问题。
- 错误用例:仍试图依赖
RCT_NEW_ARCH_ENABLED=0作为常态方案。 - 依据:仓库脚本与默认入口均体现新架构默认化(本仓源码);官方 0.82 语义也强化该方向。
- Bridgeless 下 Native Module 访问方式
- 最佳实践:理解 TurboModule 的 lazy-load 语义,必要时从 prototype 读取方法。
- 错误用例:直接
Object.keys(nativeModule)期待拿到完整方法列表。 - 依据:issue #46779(官方回复:这是设计取舍,建议
Object.keys(Object.getPrototypeOf(nativeModule)))。
- 三方库迁移节奏
- 最佳实践:在升级新架构前先评估关键依赖是否完成迁移。
- 错误用例:核心库未适配就全量开启 bridgeless,线上/测试环境直接踩崩溃。
- 依据:issue #46686(iOS bridgeless 崩溃案例,讨论指出 interop gap 与库迁移状态相关)。
- iOS Native 模块签名一致性
- 最佳实践:Swift/ObjC 导出签名严格一致,尤其是
RCT_EXTERN_METHOD对齐。 - 错误用例:Swift 方法改成
throws但导出签名未同步,触发崩溃。 - 依据:同一 issue #46686 讨论中的实战反馈。
代码级对照(可直接展示)
- iOS 依赖准备命令
错误用例(把 pod install 当唯一入口)
cd ios
pod install最佳实践(走框架命令,兼容 CocoaPods/SPM 迁移)
# Community CLI 路径
yarn ios
# Expo 路径
npx expo run:ios- Bridgeless 下 NativeModule 方法枚举
错误用例(直接枚举实例)
import {NativeModules} from 'react-native';
const mod = NativeModules.MyNativeModule;
console.log(Object.keys(mod)); // Bridgeless 下可能为空或不完整最佳实践(枚举 prototype)
import {NativeModules} from 'react-native';
const mod = NativeModules.MyNativeModule;
console.log(Object.keys(Object.getPrototypeOf(mod)));- iOS NativeModule 签名一致性(Swift + ObjC 导出)
错误用例(Swift 方法改了 throws,导出签名没变)
@objc(MyModule)
class MyModule: NSObject {
@objc func install(_ viewId: NSNumber, filterOptions: NSArray) throws {
// ...
}
}// RCT_EXTERN_METHOD 没有体现 throws 带来的签名变化,容易崩溃
RCT_EXTERN_METHOD(install:(nonnull NSNumber *)viewId
filterOptions:(nonnull NSArray *)filterOptions)最佳实践(Swift/ObjC 导出签名严格对齐)
@objc(MyModule)
class MyModule: NSObject {
@objc func install(_ viewId: NSNumber, filterOptions: NSArray) {
// ...
}
}RCT_EXTERN_METHOD(install:(nonnull NSNumber *)viewId
filterOptions:(nonnull NSArray *)filterOptions)- Android 打包任务认知(debug/release)
错误用例(把 release 也当成完全依赖 Metro)
react {
// 配错后可能导致发布变体缺 bundle
debuggableVariants = ["debug", "release"]
}最佳实践(仅将调试变体设为 debuggable)
react {
// 默认 debug 走 Metro;release 走 bundle + hermesc
debuggableVariants = ["debug"]
}可复述的一句话
“直接用 RN Core 没问题,但要顺着官方默认链路走:新架构/Hermes/工具链命令优先;一旦逆默认或混用旧心智,最容易在 bridgeless 互操作和 iOS 签名细节上出问题。”
12. Android 和 iOS 底层编译、打包分别用什么?
Android(底层工具链)
- 构建系统:Gradle + Android Gradle Plugin
- RN 集成层:React Native Gradle Plugin(RNGP)
- JS 打包:Metro bundling(由 Gradle task 调用 CLI)
- JS 编译:Hermes 编译器
hermesc(非 debug 变体常见) - SourceMap:
compose-source-maps合并 packager 与 compiler map - Native/C++:NDK + CMake(新架构库接入含自动生成的 autolinking CMake/CPP)
参考:
- 官方文档:React Native Gradle Plugin
- 本仓源码:
packages/gradle-plugin/.../ReactPlugin.kt、TaskConfiguration.kt、BundleHermesCTask.kt
iOS(底层工具链)
- 构建系统:Xcode / xcodebuild(clang/swiftc/ld)
- 依赖管理:当前主流仍是 CocoaPods(并在向 SPM 过渡)
- RN 集成层:
use_react_native!+react_native_post_install脚本体系 - JS 打包:
react-native-xcode.sh调 Metro CLI 生成 bundle/assets - JS 编译:Hermes 开启时调用
hermesc产出字节码 bundle - SourceMap:脚本阶段做 compose,保证调试可追踪
参考:
- 脚本入口:
packages/react-native/scripts/react-native-xcode.sh - Pods 入口:
packages/react-native/scripts/react_native_pods.rb
标准答法(30 秒)
“Android 侧是 Gradle + RNGP 驱动,RNGP 在变体维度编排 Metro 打包、Hermes 编译、Codegen 和 Autolinking;iOS 侧是 Xcode 构建配合 RN 的 Pods/Xcode 脚本,react-native-xcode.sh 负责 bundle 和 Hermes 字节码。两端都不是‘只打 JS 包’,而是 JS 与 Native/C++ 的联合构建流水线。”