Skip to main content

React Native

React Native 面试的绝对核心是新老架构的差异(Bridge vs JSI)渲染原理(Yoga 引擎)以及性能优化(FlatList、动画、Hermes 引擎)

常见面试题

Q1:RN 开发和 React 网页开发的核心区别是什么?重点要关注什么?

面试官意图:考察你是否有真实的 RN 开发经验,是否理解从 Web 到 Native 的思维转换。

核心区别

  1. 渲染引擎不同:网页最终渲染为 DOM,而 RN 的组件(如 <View>, <Text>)最终会被底层的 Yoga 引擎映射为真实的 Native UI 控件(iOS 的 UIView,Android 的 ViewGroup)。
  2. 样式隔离与局限
    • RN 没有 CSS 级联和全局样式,样式是内联且强隔离的。
    • 不支持 hover、不支持复杂的 CSS 动画(需使用 Animated API 或 Reanimated 库)。
  3. 事件系统差异:RN 没有 DOM 事件冒泡,取而代之的是 PanResponder 或第三方的 react-native-gesture-handler 来处理复杂的屏幕滑动和手势。

开发时必须重点关注的 3 件事

  1. 平台差异处理:iOS 和 Android 在状态栏高度、刘海屏适配(SafeArea)、键盘遮挡甚至基础组件(如时间选择器)上的表现差异极大,必须频繁使用 Platform.OS 进行分支处理。
  2. 性能与掉帧:网页里随意的一个 setState 可能只会引起微小的重绘,但在 RN 的老架构里,频繁跨 Bridge 传递数据会导致极其严重的 UI 掉帧(尤其是长列表和复杂动画)。
  3. 脱离浏览器的环境限制:没有 windowdocumentlocalStorage(用 AsyncStorage 替代),没有 Cookies(网络请求需手动在 Header 塞 Token)。

Q2:RN 中的 View 和 Web 中的 div 有什么区别?

  • 渲染本质:Web 中的 div 最终会变成浏览器 DOM 树中的一个节点;而 RN 中的 <View> 在运行时会被 Yoga 引擎计算布局,最终映射并渲染为真实的原生控件(在 iOS 上是 UIView,在 Android 上是 ViewGroup)。
  • 样式局限<View> 不支持 CSS 所有的属性(例如没有伪类 :hover,没有子选择器,所有样式只能内联或使用 StyleSheet.create)。

Q2:RN 的 Flexbox 布局和 Web 的 Flexbox 有什么不同?

虽然 RN 使用了 Flexbox 布局模型(由 Yoga 引擎实现),但与 Web 还是有一些核心差异:

  • 主轴方向不同:Web 的 flex-direction 默认是 row(水平),而 RN 的默认值是 column(垂直),因为手机屏幕通常是竖屏的。
  • 默认对齐方式不同:RN 的 alignItems 默认是 stretch
  • 属性支持不全:RN 并不支持 Web Flexbox 的所有属性(比如不支持 flex-wrap: wrap-reverse 等高级属性)。

Q3:RN 中图片加载 <Image> 为什么有时会显示不出来?

  • 网络图片必须指定宽高:在 Web 中,给 <img> 标签一个 src,浏览器加载完图片后会自动撑开宽高;但在 RN 中,加载网络图片(uri 方式)必须明确指定 widthheight,否则默认宽高为 0,图片无法显示。
  • 本地图片:使用 require('./img.png') 引入的本地图片,RN 可以在打包时获取其尺寸,因此不需要强制设置宽高。

1. 核心原理与渲染流程

React Native (RN) 的本质是:用 JavaScript 写逻辑,用原生 (iOS/Android) 渲染 UI

传统渲染流程:

  1. JS 层:React 代码运行在 JS 线程中,生成 Virtual DOM。
  2. Bridge (桥):JS 线程通过 Bridge 将 UI 更新指令序列化成 JSON 字符串,异步发送给 Native 层。
  3. Shadow 线程 (Yoga):接收到指令后,通过 Yoga 引擎(C++ 编写的 Flexbox 布局引擎)计算各个元素的实际物理大小和位置。
  4. UI 线程 (Main 线程):拿到布局信息后,调用原生控件(如 UIViewViewGroup)进行最终的渲染。

2. 架构演进:老架构 vs 新架构

在高级面试中,RN 的新老架构对比是出现频率最高的问题。

2.1 老架构 (Legacy Architecture)

老架构的三大线程(JS 线程、UI 线程、Shadow 线程)之间互相隔离,所有的通信都必须经过 Bridge

  • 致命瓶颈:Bridge 通信是异步的批处理的需要 JSON 序列化/反序列化的。如果频繁进行 JS 和 Native 之间的通信(如复杂的动画、滑动事件监听),Bridge 就会发生拥堵,导致页面掉帧、白屏。

2.2 新架构 (New Architecture)

为了解决 Bridge 的性能瓶颈,RN 团队推出了新架构,核心包含以下四大组件:

  1. JSI (JavaScript Interface)新架构的灵魂!彻底废弃了 Bridge。

    面试官高频追问:“为什么 JSI 相比 Bridge 能带来质的性能飞跃?” (核心亮点)

    • 干掉序列化开销 (内存共享):老架构下,JS 和 Native 每次通信都必须经历 JSON.stringifyJSON.parse 的漫长过程,遇到大数据结构时极其消耗 CPU 且占用内存。JSI 允许 JS 引擎直接持有 C++ 对象(HostObject)的指针引用,双方通过内存地址直接读写数据,真正实现了零拷贝 (Zero-Copy)
    • 支持同步调用 (打破异步壁垒):老架构的 Bridge 强制所有通信异步进入队列执行,导致 JS 无法实时干预 Native 的高频 UI 事件(如复杂手势、列表滚动),这是以前掉帧和白屏的元凶。JSI 允许 JS 同步调用 Native 函数,就像调用普通 JS 函数一样极速响应。
    • 引擎彻底解耦:JSI 作为一个抽象的 C++ 接口层,解除了 RN 与特定 JS 引擎的强绑定。这使得 RN 能够轻松替换掉老旧的 JSC (JavaScriptCore) 引擎,顺理成章地换上了 Meta 专为 RN 打造的高效 Hermes 引擎。
  2. Fabric (新渲染系统):基于 JSI,UI 的渲染更新变成了同步操作,这使得 RN 能够完美支持 React 18 的并发模式 (Concurrent Mode) 和 Suspense,彻底解决了快速滑动时的白屏问题。
  3. TurboModules:新一代原生模块系统。得益于 JSI,原生模块可以实现懒加载 (Lazy Load),只有在 JS 实际调用时才去初始化,大幅缩短了 App 的启动时间 (TTI)。
  4. Codegen:代码生成工具。通过静态类型(TypeScript/Flow)自动生成 C++ 接口代码,保证 JS 和 Native 通信时的类型安全。

3. 高频性能优化场景

3.1 长列表优化 (FlatList 优化)

面试官常问:“FlatList 滑动卡顿怎么优化?”

  • getItemLayout:如果列表项高度固定,提供这个方法可以跳过动态计算高度的步骤,极大提升渲染速度。
  • initialNumToRender:控制首屏渲染的条数,不要设置太大,保证首屏秒开。
  • windowSize:控制渲染窗口的大小(默认是 21,即前后各 10 屏)。适当调小可以减少内存占用。
  • removeClippedSubviews:对于大列表,开启后可以将屏幕外的视图从视图层级中移除,节省内存。
  • 不要在 renderItem 中使用匿名函数或内联对象,避免子组件不必要的重渲染。

3.2 动画优化

在老架构中,如果用 JS 线程的 requestAnimationFrame 去驱动动画,每一帧都要穿过 Bridge,必卡无疑。

  • 方案 1:开启原生驱动。使用 Animated 库时,务必加上 useNativeDriver: true。这样动画配置会一次性发给 Native 线程,由 Native 线程在 UI 线程直接执行,完全不占用 JS 线程。
  • 方案 2:使用 Reanimated 库。这是目前 RN 动画的终极解决方案,通过 Worklet 机制将动画逻辑直接运行在 UI 线程。

3.3 引擎与打包优化

  • Hermes 引擎:Meta 专为 RN 打造的 JS 引擎。核心优势是 AOT (Ahead-of-Time) 编译。它在打包阶段就将 JS 编译成了字节码 (Bytecode),使得 App 启动时不需要再解析 JS,大幅提升启动速度并降低内存占用。
  • 拆包 (Bundle Split):随着业务变大,将基础库 (React, RN) 和业务代码拆分,可以实现更高效的热更新。

4. 跨端技术横向对比 (RN vs Flutter vs WebView)

这也是一道经典的架构选型题:

特性WebView (H5/Cordova)React Native (RN)Flutter
渲染引擎浏览器内核 (Webkit/Blink)原生控件 (OEM Widgets)自研渲染引擎 (Skia/Impeller)
语言JS/HTML/CSSJavaScript / TypeScriptDart
性能最差 (受限于 DOM 和 JS 单线程)较好 (Native 渲染,但有跨语言通信损耗)最好 (直接编译为机器码,自绘 UI)
UI 一致性较好差 (依赖两端原生控件,需分别适配)极好 (像素级自绘,双端完全一致)
动态化能力极强 (随时发版)强 (支持 CodePush 热更新)极弱 (iOS 严格限制执行动态机器码)
生态与基建极度繁荣非常繁荣 (共享 npm 生态)一般 (Dart 生态相对独立)

总结话术

  • 如果对动态化(热更新)有强需求,且团队主要是前端开发,React Native 是首选。
  • 如果对性能和多端 UI 一致性要求极高,且能接受重新学习一门语言,Flutter 更胜一筹。
  • 如果只是为了在 App 里内嵌一些轻量级、经常变动的活动页,使用 WebView 即可。