React Native 原理

发布于:2025-02-28 ⋅ 阅读:(11) ⋅ 点赞:(0)

React Native 是一个跨平台移动应用开发框架,它允许开发者使用 JavaScript 和 React 来开发 iOS 和 Android 原生应用。React Native 的核心原理是通过 桥接(Bridge) 技术,使用 JavaScript 来控制原生组件,并将应用逻辑与原生代码进行交互。

React Native 原理概述

React Native 的基本原理是利用 JavaScript 线程原生线程 进行通信,构建跨平台的原生应用。具体来说,它采用了 虚拟 DOM桥接机制,使得 JavaScript 代码与原生 UI 组件能够相互协调和交互。

以下是 React Native 的工作原理的几个关键组成部分:

1. JavaScript 线程与原生线程

React Native 将应用的逻辑(JS 代码)和 UI 渲染分配给不同的线程:

JavaScript 线程:运行 JavaScript 代码的线程,主要用于执行业务逻辑和管理应用的状态。

原生线程:负责 UI 渲染和原生代码执行(例如 UIKit 或 Android Views)。这个线程会管理所有原生控件的渲染,保持 UI 的流畅性。

2. 虚拟 DOM 与 UI 渲染

React Native 使用与 React 类似的 虚拟 DOM(Virtual DOM)来管理 UI 的更新:

• 当 JS 线程发生状态变化时,React Native 会重新渲染虚拟 DOM。

• 经过差异化计算后,React Native 将更新的 UI 信息传递给原生线程。

• 原生线程通过原生控件(如 <View>、<Text>)更新应用的界面。

3. 桥接(Bridge)机制

React Native 通过 桥接(Bridge)机制来实现 JavaScript 线程和原生线程之间的通信。桥接是 React Native 的核心,它使得 JavaScript 可以调用原生模块(如相机、定位、传感器等)。

JavaScript 与原生模块的通信:通过桥接,JavaScript 线程可以向原生线程发送消息(例如发起网络请求、读取文件),并等待响应。

原生与 JavaScript 的回调:原生代码也可以通过桥接机制向 JavaScript 发送消息,从而触发 JavaScript 中的回调函数。

桥接的机制大致如下:

• JavaScript 线程执行应用逻辑,并通过桥接向原生线程发送调用请求。

• 原生线程执行请求,并通过桥接将结果返回 JavaScript 线程。

• JavaScript 根据结果更新虚拟 DOM,并最终更新原生 UI。

4. 原生组件与 JavaScript 组件

React Native 提供了封装好的 原生组件(如 <View>、<Text>、<Button> 等)和 JavaScript 组件(如业务逻辑组件)。这些组件都可以在应用中进行组合和使用。

原生组件:React Native 会将原生组件映射成原生控件。例如,<View> 在 Android 上会变成 View 控件,在 iOS 上变成 UIView 控件。

JavaScript 组件:这些组件包含业务逻辑,React Native 会通过桥接机制与原生 UI 组件进行交互。

5. 异步执行和多线程

React Native 是基于异步编程的:

UI 渲染线程JS 执行线程是独立的,彼此并行工作,避免了阻塞和卡顿。

异步调用:大部分与原生模块的交互都是异步的,这可以避免主线程被阻塞,确保 UI 渲染的流畅性。

批量更新:React Native 会将一系列 UI 更新合并为一次更新,从而减少不必要的渲染,提高性能。

6. React Native 的架构图

在 React Native 的架构中,通常会有以下几个部分:

1. JS 层:

• 编写的 JavaScript 代码运行在 JavaScript 引擎(如 V8 或 JavaScriptCore)中,负责应用逻辑、状态管理、业务处理等。

2. React 层:

• React 负责 UI 的状态管理和虚拟 DOM 渲染。它与原生层通过桥接进行通信。

3. 桥接(Bridge)层:

• 充当 JavaScript 层和原生层之间的中介。所有的 JS 与原生组件的交互都通过这个桥进行。

4. 原生层:

• 包含原生 UI 组件和原生代码,直接与操作系统交互(如 UI 控件、文件系统、传感器等)。

另一个层面理解:

  • Java层: 主要负责 Native 的 UI 渲染和底层功能调用, Java 层的核心 jar 包是 react-native.jar, 封装了很多接口, 例如 Module, Registry, Bridge
  • C++层: 主要封装了 JavaScriptCore, 起到了解析 JS 代码的作用
  • JS 层: 利用 JS 代码去进行事件的分发和 UI 代码的编写, 主要以下几部分:
    • Component: 编写 JSX 来构建虚拟 DOM
    • Lifecycle: 生命周期必不可少, 可以在组件的各种时期器进行一些操作
    • Layout: 使用 FlexBox 进行布局, 用 css-layout, 不依赖 DOM, 可以编译成 Native 端代码, 用于布局样式的展示, 目前不支持 CSS3


 

RN 现在主要有 3 个线程

  1. JS Thread 执行线程, 负责逻辑层面的处理, Metro 将 React 源码打包成 bundle 文件, 然后传给 JS 引擎执行, 现在 IOS 和 Android 统一的是 JSC
  2. UI Thead 主要主责原生渲染 Native UI 和调用原生能力 (Native Module)
  3. Shadow Thead 这个线程主要创建 Shadow Tree 来模拟 React 结构树, RN 使用 Flexbox 布局, 但是原生不支持, Yoga 引擎就是将 Flexbox 布局转换为原生布局的

7. 如何实现跨平台

React Native 的跨平台特性主要依赖于以下两点:

组件封装:React Native 提供的核心组件是跨平台的,例如 <View>、<Text> 等,它们在 Android 和 iOS 上都能渲染为各自原生平台的 UI 控件。

平台差异处理:React Native 允许开发者通过 Platform API 来处理不同平台之间的差异,做出平台特定的调整。

• 例如:Platform.OS === 'ios' 用于判断当前平台是 iOS,Platform.select() 可用来为不同平台选择不同的组件或样式。

8. 开发和调试

React Native 提供了良好的开发体验:

热重载:React Native 支持热重载(Hot Reloading),即修改代码后,应用会立即重新加载,只更新修改过的部分,提升开发效率。

远程调试:开发者可以通过 Chrome 浏览器调试 JavaScript 代码,方便排查问题。

9. 原生模块和库

如果 React Native 中没有提供某些功能,开发者可以通过原生模块或第三方库来扩展 React Native:

原生模块:使用原生语言(Java/Kotlin 或 Objective-C/Swift)编写,暴露给 JavaScript 使用。

第三方库:React Native 社区有很多开源的第三方库,可以在应用中使用它们来快速实现功能。

总结

React Native 的原理通过 JavaScript 和原生代码之间的桥接实现了跨平台的能力。它通过将业务逻辑与 UI 渲染分开,采用虚拟 DOM 和异步执行机制,能够在 iOS 和 Android 上以接近原生的性能和体验运行。同时,它保持了 React 风格的声明式编程,减少了开发者的工作量。

拓展

React Native 的不足

由于 React Native 和原生交互依赖的只有一个 Bridge,而且 JS 和 Native 交互是异步的,所以对需要和 Native 大量实时交互的功能可能会有性能上的不足,比如动画效率,性能是不如原生的

React Native 始终是依赖原生的能力,所以摆脱不了对原生的依赖,相对 Flutter 的自己来画 UI 来说,React Native 显得有些尴尬。

和其他跨端技术比较

Flutter vs React Native

开发体验

React Native 在界面开发延续了 React 开发风格,支持 css-in-js(其实就是用 js 来写 css),而且在 0.59 版本之后支持了 React Hook 函数式编程,开发的时候大多只关心样式界面的搭建,原生能力有客户端或者 Bridge 实现。

Flutter 最大的特点在于:Flutter 是一套平台无关的 UI 框架,并且在 Flutter 里面万物皆 Widget。很多时候开发一个控件需要嵌套多个 Widget 去实现,与 JS 里面的回调地狱有点像,而这也是被吐槽代码嵌套样式难看的原因。

状态管理

React Native 和 Flutter 对于状态管理,两者有着很高的相似度,虽然内部实现很大差别,但是都可以获取 state 和 setState 的方式去更新页面的状态。

产物

React Native 产生的是 bundle 文件,实际上就是 JS 脚本文件;而 Flutter 编译后 Android 产生的主要是一些应用程序指令段、数据段,虚拟机数据段、指令段,iOS 则是 App.framework,其实也是一些原生的数据集。

原生能力 & 性能

其实两者的在这方面的区别不是很大,性能方面 React Native 稍微差一点。但是在原生灵活性上 React Native 要有优势。


JSI

javascript interface js虚拟机通用接口层,是针对JS引擎封装的上层API框架,使用JSI做JS引擎调用的优点:

1.底部可以任意替换JS引擎而不影响上层JS引擎的使用。如:可以任意替换JavaScript Core, V8等。

2.通过JSI,JavaScript可以持有C++宿主对象的引用,所以可以直接调用原生方法(UIView, NativeModule),它与现在统一使用Bridge这个通道和消息异步调用比起来,提高了消息发送的及时性,避免了消息队列执行的等待。