随着 React
的盛行,其移动开发框架 React Native
也收到了广大开发者的青睐,如下简称 RN。经过 RN 咱们可以使用 JavaScript 语言来实现跨平台移动应用的开发,打开了前端工程师通往移动平台的大门。用 RN 官方的介绍来归纳它的特色就是:Learn once, write anywhere
。javascript
若是你了解 React,那么学习 RN 的话应该会很是轻松。由于 RN 和 React 使用了相同的开发语言 JavaScript 和相同的设计理念 React,在 React 的基础上添加了原平生台的底层支持。这样,不一样平台的适配就交由 RN 去处理,而开发者只须要关注 RN 平台应用开发自己。html
本文将从 RN 混合开发(与 iOS、Android 平台交互)的原理和实现进行介绍,结合流程图的方式让你们进一步的了解 RN 开发的思想和底层逻辑。前端
先来看一个使用 RN 实现的简单的 Hello world 展现:java
上方咱们不难看到一些很熟悉的 React 语法,但除此以外咱们还能看到其引入了 react-native
库中的 AppRegistry API 和 Text (文本)组件,这即是 RN 提供给咱们用于调用原平生台的 APIs 和 组件,其可以在不一样移动设备上实现一致的功能和逻辑。最后展现在 APP 中的即是 Hello world 文本,而至于 AppRegistry API 后面会作相应介绍。react
那么看完 Hello world 示例后,咱们应该大体知道了 RN 应用的一个结构,咱们用图例的方式进行解刨说明,以下图所示:android
从图中能够看到,咱们整个的 RN 应用能够分为两层展现:ios
也能够理解为所谓的应用层和底层。应用层经过 JavaScript 桥接层
与底层平台进行交互,获取底层平台的原生 APIs、UI 组件及一些自定义组件等。好比 Hello world 示例中引入的 AppRegistry API 和 Text 组件即是很好的说明。git
这样的分层可以使应用层的开发变得简单、高效和跨平台,对于应用的稳定性、运行时的性能来讲将和原平生台保持接近。github
大体了解完 React Native 应用的结构后,咱们不妨再来认识下原平生台是如何调用 React Native 组件的。咱们 RN 的代码要跑在原生 APP 中那必然须要原生 APP 加载运行对应的 RN 组件,以实现混合开发和交互的功能。这里就要来介绍下刚刚搁置的 AppRegistry API 了。redux
通常咱们的 RN 项目都会有一个入口文件,好比 index.js(老版本会存在两个:index.ios.js 和 index.android.js)用于注册根组件并提供给原平生台运行。这里的注册根组件就要经过 AppRegistry API 来实现。
咱们须要在根组件里调用 AppRegistry 中的 registerComponent
方法进行组件的注册。注册完以后原平生台即可以经过 runApplication
方法来运行注册过的根组件。须要注意的是注册和运行的组件名称二者必须保持一致,这样才可以实现加载对应的组件。好比 Hello world 示例中咱们注册的根组件名为 HelloWorldApp,而且注入相应的组件模块。另外同时一个入口文件中,咱们也能够注册多个根组件。
刚刚在介绍原平生台调用 RN 组件时提到了加载对应根组件的功能。那么是否是原平生台只有经过不断的调用运行 RN 注册的根组件才能实现不一样页面的首次加载呢(这里的加载指原生打开 RN 页面)?答案是否认的。
除了上述经过调用不一样的根组件来实现原生打开不一样的 RN 界面外(图中第二点),咱们还能够调用一个根组件来实现。惟一的区别在于咱们须要调用时在 initialProperties 中添加区分不一样界面的标识位来渲染不一样的组件,就比如在 URL 上携带不一样参数跳转到同一路由同样,根据路由上的参数在应用层进行对应组件的渲染。
在 RN 根组件中咱们能够经过 this.props
获取原平生台携带过来的参数对象,如示例中的 viewName,再根据 viewName 实现 RN 内部组件的渲染,固然也能够结合 react-navigation
来实现路由模块的切换。至于最终选择哪一种方式加载,决定权仍是要看业务的划分和功能的定义。相比较而言第一种可能更加灵活和便捷。
在混合开发模式下,咱们不可避免的须要和原平生台进行数据的通讯,那么在 RN 中,咱们如何与原平生台进行通讯呢?如何获取原平生台提供的数据或将数据传递给原平生台呢?下面这张图便介绍了这一流程。
在 RN 中,咱们能够引用 react-native 模块中的 NativeModules
API 来进行数据通讯,调用的方法是 NativeModules.模块名称.接口名称,而原平生台返回数据到 RN 平台是基于回调,代码以下:
import { NativeModules } from 'react-native';
const userInfo = NativeModules.UserInfo; // 获取自定义用户信息模块
console.log(userInfo.userName); // 打印用户名
const router = NativeModules.Router; // 获取自定义路由模块
// 调用原生路由跳转方法
router.openHome('参数', (res) => {
console.log(res); // 打印返回数据
});
复制代码
经过 NativeModules 咱们能够灵活的获取或传递数据给原平生台,同时咱们也能够根据业务须要编写不一样的 Bridge
方法来实现数据通讯模块的封装,好比用户信息模块、路由跳转模块及网络请求模块等。
在 RN 项目中,除了与原平生台通讯和交互的功能外,RN 平台自身也须要实现一些数据状态的管理。这里咱们还得认识下 Redux 架构。
Redux 是一个用于管理 React 应用状态的容器,在 RN 中也一样适用。其采用单一数据流的方式来实现数据的管理,惟一改变 state 的方法是提交 action 操做。这样的架构使得咱们的 RN 项目数据易于维护或扩容,改变数据的流程容易追踪和捕获。须要了解的具体关键字以下:
具体文档能够参考:cn.redux.js.org/
固然你也可使用其余第三方库实现相似的架构,好比 mobx、dva 等。
除了 Redux 架构,RN 中还加入了 CSS in JS
的概念,将本来关注点分离的理念转移到了关注点混合上,使得咱们能够在 JS 中写 CSS 代码,但这并不违背以前关注点分离的理念。
如今随着组件化概念的流行,对从组件层面维护 CSS 样式的需求日益增大,CSS-in-JS 就是在组件内部使用 JavaScript 对 CSS 进行了抽象,能够对其声明和加以维护。这样不只下降了编写 CSS 样式带来的风险,也让开发变得更加轻松。它和 CSS Modules 的区别是再也不须要 CSS 样式文件。
结合 JSX 语法,在 RN 中书写和维护 CSS 变得更加便捷,也是 Web 组件化不断发展的必然产物。
另外,在开发 RN 项目时,官方推荐使用的布局方式是 Flex
布局,由于 Flexbox 能够在不一样屏幕尺寸上提供一致的布局结构,这也解决了跨平台布局呈现的问题。
相比咱们客户端使用的 Flex 布局,RN 中的 Flex 布局有稍许的不一样,好比 flexDirection 的默认值是 column 而不是 row,flex 也只能指定一个数字值等。关于 Flex 布局的介绍能够参考:Flex 布局教程:语法篇、Flex 布局教程:实例篇
最后咱们介绍下 RN 中的热部署,这也是选择 RN 开发 APP 的一个重要缘由之一。相比传统 APP 更新,大都须要第三方审核的流程,而这个流程可能会很慢或者不及时,遇到须要紧急修复的 bug 没法及时更新而致使直接的经济损失是很常见的问题,而 RN 的热部署能够必定程度上解决或减轻这一问题的影响。那么其实现原理是怎样的呢?
上图左侧部分便展示了用户访问 RN 应用的热部署流程。首先用户访问 APP,APP 会向 RN 服务器请求资源包,若是资源包未更新则读取本地缓存资源,若是开发者为了解决 bug 从新更新了服务器上的资源包,那么 APP 拉去后会缓存起来,待用户下次进入后再进行更新。这即是 RN 热部署的流程。
在本地开发时,咱们不难发现当咱们在运行起来的 RN 项目中修改代码时,再次从 APP 进入 RN 页面,本地终端会再次加载一次更新后的资源数据,这也是 RN 热部署的体现。
一样线上的热部署则须要将咱们打包后的 RN 资源上传到服务器上供 APP 读取来实现。
咱们能够手动执行打包、上传发布流程,固然为了减小人为干预,实现前端自动化,咱们也能够把这块流程交给构建平台去自动打包部署,这便须要搭建一个后台系统进行管理。
本文介绍了 React Native 混合开发的原理与实现逻辑。只有先了解原理,才能高效的投入项目的开发中,而关于 RN 自身的功能实现你们能够直接阅读官方文档,这里我也额外提供一些关于 RN 的参考资料:
注:本文部分图例参考自《React Native 移动开发实战》一书