隨着 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 移動開發實戰》一書