【譯】關於React Native在專業用於多種規模項目後的思考

React Native已經存在了一段時間了。當Android支持發佈時(iOS發佈後大約一年),我把它用於專業。我決定投入時間進行跨平臺開發。當我發現React Native時,我已是iOS開發人員已經有6年了,並且不只僅是Mac OS X開發人員。react

我在App Store和Play商店爲個人客戶開發了四個中等大小(不包括依賴項的10,000-20,000行代碼)項目。我還負責監督和貢獻了一個更大的項目,其中包含50,000多行使用React Native編寫的代碼(除了native代碼),如今正在生產環境中部署並運行順利。我已經積累了足夠的經驗來找出React(和React Native)的亮點,以及它不在哪裏 - 以及如何擴展它。android

注意:我知道大家中的一些人在閱讀這篇文章時會指向Flutter。因爲它的成熟度遠不及它的競爭對手,我尚未考慮它。git

在撰寫本文時,React Native的當前穩定版本爲0.57,即將有0.58RC。

如下是個人想法:github

React Native最廣爲人知也是最不重要的的功能

React Native最廣爲人知的功能是它是跨平臺的,但這並非它引發我注意的緣由。 React Native最重要的特性是它使用React,這樣它支持一個通用的聲明性佈局。跨平臺支持排在第二位。做爲一名iOS開發人員,我一直在努力設計用戶界面的方式不那麼直觀;自動佈局系統。數據庫

若是您的系統具備高度動態性,而且屏幕上的元素相互依賴(如抽屜和動畫),那麼Apple的Autolayout是管理屏幕上內容的最佳方式。可是,對於大多數Android和iOS應用程序,狀況並不是如此。大多數Android和iOS應用程序都使用咱們習慣看到的標準元素:文本,按鈕,列表,通用視圖和圖像以最相似於Web的方式佈局。編程

在AutoLayout發明之間的時間裏,FlexBox系統被髮明並用做將事物放在屏幕上的事實標準。除了標準的Web使用以外,還有一些佈局系統旨在利用FlexBox原則進行原生開發:react-native

有更多的接口庫 - 這些只是衆所周知的一些。他們有一個共同點,就是他們都使用聲明式用戶界面方法。bash

聲明性用戶界面的狀況:

建立移動開發的聲明性用戶界面是爲了解決傳統佈局系統所具備的問題。您聲明瞭您的意圖,系統會根據它們生成結果。架構

聲明性用戶界面解決的移動開發挑戰不多以下:函數

組件化。 iOS在ViewControllers中使用ViewControllers並在視圖中查看。 Android使用Fragments。二者都具備XML接口聲明,而且都容許運行時視圖實例化和編輯。當涉及將它們分解爲較小的或重用它們時,你就是在進行一個小型的重構。在聲明性用戶界面中,默認狀況下已經具備此功能。

開發者生產力。聲明性用戶界面負責爲您調整組件大小。看看這段代碼(React Native示例):

class TestTextLabel extends React.Component {
  render() {
    return (
      <view>
        <text>This is a small text</text>
        <text>{this}</text>
      </view>
    );
  }
}
複製代碼

上面的代碼渲染了一個只包含兩個文本組件的Component。注意this.props.sampleText。若是此變量太長(例如 - 10000個字符長)會發生什麼?結果將是組件將調整大小以適合整個文本。若是文本到達容許空間的末尾(屏幕,讓咱們說),那麼視圖將被剪切,用戶將沒法看到整個文本。你須要一個滾動視圖。

class TestTextLabel extends React.Component {
  render() {
    return (
      <ScrollView style={{flex : 1}}>
        <Text>This is a small text</Text>
        <Text>{this}</Text>
      </ScrollView>
    );
  }
}
複製代碼

惟一改變的是添加<ScrollView>元素。若是是在iOS上,這須要進行更多工做。

協做 - Git Friendliness。我見過的每一個聲明性UI都更好。

在iOS和Android上,若是你有大塊UI,那你就作錯了。可是,大型XML文件在大多數狀況下是不可避免的(對於iOS來講:XIB其實是XML文件)。它們的變化對代碼審查者(或您)來講沒有任何意義 - 若是您不一樣意之前哪一個版本(您或者其餘開發人員的更改)保持完整,則拉動請求幾乎是不可能的。

使用React和其餘聲明性UI庫,這些問題在很大程度上被最小化,由於佈局是實際代碼 - 您能夠更新,刪除,合併,差別以及執行您一般對軟件的任何其餘部分執行的全部操做的代碼。

關鍵是要了解「性能」到底是什麼

您可能須要成爲移動開發人員才能掌握性能概念並管理有效的內存和處理器使用。

Web開發人員能夠在不瞭解Native的狀況下使用React Native的概念僅適用於小型項目。一旦應用程序開始增加而且Redux商店的計算開始對應用程序的性能形成影響,您將須要瞭解Native端如何工做以瞭解爲何會發生這種狀況。您還須要意識到React Native中的Redux Store致使的從新渲染與DOM中發生的從新渲染並不徹底相同。這尤爲適用於來自應用的Native端的組件。

同時,在React Native上從新渲染應用程序的組件會變得昂貴。因爲React Native使用橋接器,所以您在render()函數內提供的任何指令都將從JavascriptCore傳遞到Java / Objective C ++。native端將採用JSX標記中給出的render()指令,並將它們轉換爲其native對應項,如視圖,標籤和圖像。若是每秒進行數百次,那種翻譯須要不可忽略的cpu時間。

在性能部門,彷佛React Native是更好的跨平臺解決方案之一。可是,在某些關鍵領域仍然存在React Native的性能問題。

一個這樣的例子是大型數據集(和列表)。在大型列表和網格視圖的狀況下,Android和iOS提供了一個出色且極其靈活的解決方案 - 回收視圖。想象一下,當使用大型列表視圖(iOS / Android)時,只渲染在任何給定時間顯示的單元格。其餘單元格被標記爲可重複使用,以便在即將顯示新單元格時能夠重複使用它們。更改數據集時,操做系統只需更新顯示的單元格。

React Native爲大型數據集提供VirtualizedList及其派生(FlatList和SectionList)。然而,即便這樣也有不少不足之處。存在性能開銷,尤爲是在SectionList中渲染複雜組件並嘗試更新100多個對象的大型數據集時。更新機制使低端或中端移動設備運行緩慢。

爲了解決這個問題,我已經從Redux切換到MobX,它爲個人組件提供了更可預測的更新。此外,在大型列表的狀況下,MobX能夠更新特定單元而無需從新呈現整個列表。一般這也能夠經過Redux實現,可是您須要覆蓋componentShouldUpdate()並編寫更多樣板文件以免沒必要要的從新渲染。在將其他變量複製到新狀態時,您的reducer仍會執行一些沒必要要的工做。

底線:當心。您使用React Native的事實意味着從您的應用程序實現最佳性能須要熟悉React的最佳實踐和Native實踐。

瞭解JS運行時及其對您的影響很是重要。

能夠經過將調試信息發送到Chrome的網橋在React Native中進行調試。這意味着在設備中運行實際代碼的過程與您調試代碼的過程不一樣。

Android和iOS上的React Native使用JavascriptCore執行Javascript。可是,調試工具在V8(Chrome)上運行。爲了使系統更加分散,在撰寫本文時,React Native在iOS上使用Apple的Javascript Core,而在Android上,他們使用的是3年前JS Core的構建腳本(由於Android沒有提供任何JS運行時)像iOS這樣的盒子Facebook必須本身構建)。這致使缺少JS功能,如Android上的代理對象支持和64位支持。所以,若是你想使用MobX 5+他/她是運氣很差,除非你使用升級的Javascript運行時(繼續閱讀以瞭解如何作到這一點)。

運行時差別一般會致使錯誤只能在生產中重現。更糟糕的是,有些事情會變得難以辨認。

例如,當涉及React Native時,移動數據庫的最佳解決方案是Realm。可是,當進入調試模式時,會發生這種狀況:https://github.com/realm/realm-js/issues/491。 Realm的人已經解釋了爲何會這樣 - 但最重要的是,若是咱們想要一個更穩定的調試解決方案,必須改進React Native的調試架構。好消息是我一直在使用Haul做爲個人捆綁包,它容許我直接從個人iOS設備進行調試,而無需經過Chrome Dev Tools(不幸的是,你須要Mac,iOS模擬器和Safari)。

請注意,Facebook上的人已經知道這個問題,他們正在從新設計React Native的核心,以便Native和React Native部分能夠共享相同的內存。完成此操做後,可能能夠直接在設備的JavaScript運行時上進行調試。 React Native Fabric(UI-Layer Re-architecture)

不只如此,React Native社區如今提供了js android構建腳本,容許構建更新版本的JavascriptCore並將其嵌入到React Native應用程序中。這使Android的React Native Javascript功能與iOS相提並論,也爲在Android上運行的React Native增長了64位支持鋪平了道路。

使用React Native進行應用內導航很是棒

您是否開發過帶身份驗證的移動應用程序?若是用戶收到推送通知而且必須首先經過登陸屏幕,而且只有在登陸後他才能看到推送通知內容屏幕,會發生什麼?或者,若是您當前深深嵌套在應用程序中並但願跳轉到另外一個應用程序部分中的徹底不一樣的區域做爲對用戶操做的響應,該怎麼辦?

像Native這樣的問題能夠經過一些努力在Native中解決。使用React Navigation,它們甚至都不是問題。與相關路線和導航跳躍的深度連接感受天然和流暢。還有其餘導航庫,但React Navigation被認爲是事實上的標準。你應該試一試。這是React Native比iOS和Android更好的方式。

React Native is not a silver bullet

與任何其餘技術同樣,您須要在投資以前瞭解它是什麼以及它是什麼。如下

  • 是關於RN擅長什麼的非詳盡列表:
  • 內容驅動的應用程序
  • 具備相似Web的UI的應用程序。
  • 跨平臺應用程序可能須要或可能不須要快速上市時間。

這裏還有一份非詳盡的清單描述RN還差的很遠的地方:

  • 具備巨大列表的應用程序
  • 媒體驅動的應用程序無需佈局(例如:簡單/小型遊戲,動畫,視頻處理)或屏幕到屏幕的過渡。
  • CPU密集型任務。

確實,對於React沒法作到的事情,您能夠在Native中編寫所需的全部內容,而後從React Native調用相應的代碼。但這意味着您須要爲每一個平臺(iOS,Android)編寫一次代碼,而後爲Javascript接口編寫額外的代碼。

React Native的內部組件目前正在經歷一個主要的重構,所以RN能夠並行地同步執行更多操做,以便它能夠與Native共享公共代碼。 facebook.github.io/react-nativ… - 在此以前,您應該在決定是否使用它以前進行一些研究。

結論

React Native是一個通過深思熟慮且發展良好的平臺。它爲您的應用打開了NodeJS的世界,並讓您在其中一個最好的佈局系統中進行編程。它還爲您提供了與Native方面的良好橋樑,以便您能夠充分利用這兩個世界。

然而,它也屬於另外一個奇怪的類別 - 你須要一個或三個團隊開發你的應用程序!在某些時候,您須要一些iOS和Android開發人員來構建React Native默認狀況下沒有的組件。一旦您的團隊開始成長,您將不得不決定是否將您的應用程序設爲100%Native。所以,不管您爲下一個項目選擇React Native,都會成爲您須要擁有多少Native代碼(Java / Kotlin / Swift / ObjC)的問題。

我我的的建議:若是你意識到你須要3個團隊來開發一個應用程序的三個方面(一個iOS團隊,一個Android團隊和一個React團隊)那麼你應該能夠一直使用原生iOS和Android並跳過React Native 。經過僅維護兩個代碼庫而不是開發三個代碼庫,您將節省時間和金錢。

可是,若是你有一個由熟練的開發人員組成的小團隊,而且想要構建一個內容應用程序或相似的東西,那麼React Native是一個很好的選擇。

相關文章
相關標籤/搜索