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

敲鐘人Quasimodo發表於2019-01-14

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

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

注意:我知道你們中的一些人在閱讀這篇文章時會指向Flutter。由於它的成熟度遠不及它的競爭對手,我還沒有考慮它。

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

以下是我的想法:

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

React Native最廣為人知的功能是它是跨平臺的,但這並不是它引起我注意的原因。 React Native最重要的特性是它使用React,這樣它支援一個通用的宣告性佈局。跨平臺支援排在第二位。作為一名iOS開發人員,我一直在努力設計使用者介面的方式不那麼直觀;自動佈局系統。

如果您的系統具有高度動態性,並且螢幕上的元素相互依賴(如抽屜和動畫),那麼Apple的Autolayout是管理螢幕上內容的最佳方式。但是,對於大多數Android和iOS應用程式,情況並非如此。大多數Android和iOS應用程式都使用我們習慣看到的標準元素:文字,按鈕,列表,通用檢視和影像以最類似於Web的方式佈局。

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

有更多的介面庫 - 這些只是眾所周知的一些。他們有一個共同點,就是他們都使用宣告式使用者介面方法。

宣告性使用者介面的情況:

建立移動開發的宣告性使用者介面是為了解決傳統佈局系統所具有的問題。您宣告瞭您的意圖,系統會根據它們生成結果。

宣告性使用者介面解決的移動開發挑戰很少如下:

元件化。 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是一個很好的選擇。

相關文章