在Android,iOS,Web和跨平臺框架的橫向對比中,React Native自己是一個相對較新且快速開發移動的平臺。兩年後,咱們能夠確定地說React Native在不少方面都是革命性的。這是移動設備的範例轉變,咱們可以從中受益不少。然而也有明顯的痛點,它的優勢不只僅是這些javascript
跨平臺
React Native
的主要好處是,您編寫的代碼能夠在Android和iOS上本機運行。使用React Native的大多數功能都可以實現95-100%的共享代碼,0.2%的文件是特定於平臺的(android.js / ios.js)。css
統一設計語言系統(DLS)
咱們開發了一種名爲DLS的跨平臺設計語言。咱們有Android,iOS,React Native和每一個組件的Web版本。擁有統一的設計語言能夠編寫跨平臺功能,由於它意味着設計,組件名稱和屏幕在不一樣平臺上是一致的。可是,咱們仍然能夠在適用的狀況下作出適合平臺的決策。例如,咱們使用Android 上的原生工具欄和iOS 上的UINavigationBar,咱們選擇隱藏Android上的披露指標,由於它們不符合Android平臺設計指南。html
咱們選擇重寫組件而不是包裝本機組件,由於爲每一個平臺單獨製做適合平臺的API更加可靠,並減小了可能不知道如何正確測試React Native中的更改的Android和iOS工程師的維護開銷。可是,它確實會致使同一組件的本機版本和React Native版本不一樣步的平臺之間出現碎片。java
react
React是最受歡迎的 Web框架。它簡單而強大,能夠很好地擴展到大型代碼庫。咱們特別喜歡它的特色:node
迭代速度
在React Native中進行開發時,咱們可以在一兩秒內可靠地使用熱從新加載來測試Android和iOS上的更改。儘管構建性能是咱們原生應用程序的首要任務,但它從未接近咱們使用React Native實現的迭代速度。充其量,本機編譯時間爲15秒,但完整版本可能高達20分鐘。react
基礎環境的搭建成本
咱們開發與本機基礎架構是普遍集成。全部核心部分(如網絡,國際化,測試,共享組件轉換,設備信息,賬戶信息等)都包含在一個React Native API中。這些橋接是一些比較複雜的橋接,由於咱們但願將現有的Android和iOS API包裝成React的一致和規範。雖然經過快速迭代和新基礎設施的開發使這些橋接保持最新狀態是一個不斷追趕的遊戲,但基礎設施團隊的投資使產品開發工做變得更加容易。android
若是不對基礎環境進行大量投入,ReactNative將致使下降開發人員和用戶體驗。所以,咱們不相信React Native能夠簡單地添加到現有應用程序而無需大量持續投入。ios
性能
React Native最大的擔心之一就是它的性能。可是,在實踐中,出現的次數相對來講仍是比較少的。咱們的大多數React Native屏幕都像咱們的原生屏幕同樣流暢。性能一般被認爲是單一維度。咱們常常看到移動工程師看JS並認爲「比Java慢」。可是,在許多狀況下,從主線程移動業務邏輯和佈局實際上改善了渲染性能。css3
當咱們確實看到性能問題,他們一般由過多的渲染引發的有效利用是緩解shouldComponentUpdate,removeClippedSubviews,並更好地利用終極版。git
可是,初始化和首次渲染時間(以下所述)使得React Native在啓動屏幕,深層連接方面表現不佳,而且在屏幕之間導航時增長了TTI時間。此外,丟幀的屏幕很難調試,由於Yoga在React Native組件和本機視圖之間進行轉換。
Redux
咱們使用Redux進行狀態管理,咱們發現它有效並阻止UI與狀態不一樣步,並在屏幕上輕鬆實現數據共享。然而,學習曲線相對困難。咱們爲一些常見模板提供了生成器,但在使用React Native時,它仍然是最具挑戰性的部分之一和混淆源。值得注意的是,這些挑戰並不是特定於React Native。
由Native支持
由於React Native中的全部內容均可以經過本機代碼進行橋接,因此咱們最終可以構建許多咱們在開始時不肯定的內容,例如:
動畫
感謝React Native Animated庫,咱們可以實現無抖動的動畫甚至是交互驅動的動畫,例如滾動視差。
JS / React開源
由於React Native真正運行React和javascript,因此咱們可以利用極大的javascript項目,如redux,reselect,jest等。
Flexbox的
React Native使用Yoga處理佈局,這是一個跨平臺的C庫,可經過flexbox API 處理佈局計算。在早期,咱們受到瑜伽限制的影響,例如缺少寬高比,但它們已在後續更新中添加。此外,有趣的教程,如flexbox froggy使入門更加好玩。
與Web協做
在React Native探索的後期,咱們當即開始爲web,iOS和Android構建。鑑於Web也使用Redux,咱們發現大量代碼能夠在Web和本機平臺之間共享而無需更改。
React Native
React Native不如Android或iOS成熟。它更新,更雄心勃勃,移動速度極快。雖然React Native在大多數狀況下都能很好地運行,但有些狀況下,它的不成熟表現出來而且在本地調試某一些bug很難解決。不幸的是,這些實例很難預測,可能須要幾個小時到幾天才能解決。
維護React Native的分支
因爲React Native的不成熟,咱們有時須要修補React Native源。除了回饋React Native以外,咱們還必須維護一個fork,咱們能夠快速合併更改並突破咱們的版本。在這兩年中,咱們不得不在React Native之上添加大約50個提交。這使得升級React Native的過程很是痛苦。
JavaScript工具
JavaScript是一種無類型語言。缺少類型安全性難以擴展,也成爲移動工程師爭論的焦點,由於他們習慣於輸入可能對學習React Native感興趣的語言。咱們探索了採用流程,但隱祕的錯誤消息致使使人沮喪的開發人員體驗。咱們還研究了TypeScript,可是將它集成到咱們現有的基礎設施中,例如babel和metro bundler,這被證實是有問題的。可是,咱們正在繼續積極研究網絡上的TypeScript。
重構
JavaScript沒法解決的反作用是重構很是困難而且容易出錯。重命名道具,尤爲是具備通用名稱的道具,如onClick或經過多個組件傳遞的道具,這些都是精確重構的噩夢。更糟糕的是,重構在生產中而不是在編譯時中斷,而且很難添加適當的靜態分析。
JavaScriptCore不一致
React Native的一個微妙而棘手的方面是因爲它是在JavaScriptCore環境中執行的。如下是咱們遇到的後果:
React Native開源庫
學習平臺既困難又耗時。大多數人只知道一兩個平臺。具備本地橋(例如地圖,視頻等)的React Native庫須要全部三個平臺的相同知識才能成功。咱們發現大多數React Native Open源項目都是由只有一兩個經驗的人編寫的。這致使Android或iOS上出現不一致或意外錯誤。
在Android上,許多React Native庫還要求您使用node_modules的相對路徑,而不是發佈與社區所指望的不一致的maven工件。
並行基礎設施和功能工做
咱們在Android和iOS上積累了多年的原生基礎設施。可是,在React Native中,咱們從一個空白的平板開始,不得不編寫或建立全部現有基礎架構的橋樑。這意味着有時候產品工程師須要一些尚不存在的功能。在那時,他們要麼必須在他們不熟悉的平臺上工做,要麼在他們的項目範圍以外進行構建,要麼被阻止直到能夠建立它。
APP崩潰監控
咱們使用Bugsnag在Android和iOS上進行崩潰報告。雖然咱們可以讓Bugsnag在兩個平臺上都能正常工做,但它的可靠性較低,須要的工做量比其餘平臺要多。由於React Native在業界相對較新且不多見,因此咱們必須構建大量的基礎設施,例如在內部上傳源映射,而且必須與Bugsnag一塊兒工做,以便可以執行過濾崩潰等事情。反應原生。
因爲React Native周圍的自定義基礎架構數量不少,咱們偶爾會遇到嚴重的問題,即未報告崩潰或源地圖未正確上傳。
最後,若是問題跨越React Native和本機代碼,調試React Native崩潰一般更具挑戰性,由於堆棧跟蹤不會在React Native和native之間跳轉。
橋接
React Native有一個橋接API,用於在本機和React Native之間進行通訊。雖然它按預期工做,但編寫起來很是麻煩。首先,它須要正確設置全部三個開發環境。咱們還遇到了不少問題,其中來自JavaScript的類型是出乎意料的。例如,整數一般用字符串包裹,這個問題直到經過橋接纔會實現。更糟糕的是,有時iOS會在Android崩潰時無聲地失敗。咱們開始研究從2017年末開始自動生成TypeScript定義的橋接代碼,但實在太晚了。
初始化時間
在React Native第一次呈現以前,必須初始化其運行時。不幸的是,即便在高端設備上,這對於咱們的應用程序來講也須要幾秒鐘。這使得使用React Native用於啓動屏幕幾乎是不可能的。咱們經過在app-launch處初始化它來最小化React Native的首次渲染時間。
初始渲染時間
與原生屏幕不一樣,渲染React Native須要至少一個完整的主線程 - > js - >瑜伽佈局線程 - >主線程往返纔有足夠的信息來首次渲染屏幕。咱們在iOS上看到平均初始p90渲染時間爲280毫秒,而在Android上則爲440毫秒。在Android上,咱們使用了postponeEnterTransition API,它一般用於共享元素轉換,以延遲顯示屏幕,直到它呈現爲止。在iOS上,咱們遇到了從React Native快速設置導航欄配置的問題。所以,咱們在全部React Native屏幕轉換中添加了50ms的人爲延遲,以防止導航欄在加載配置後閃爍。
應用大小
React Native對應用程序大小的影響也不容忽視。在Android上,React Native(Java + JS +本地庫,如Yoga + Javascript Runtime)的總大小爲每一個ABI 8mb。在一個APK中使用x86和arm(僅32位),它將更接近12mb。
64位
因爲此問題,咱們仍然沒法在Android上發送64位APK 。
手勢
咱們避免將React Native用於涉及複雜手勢的屏幕,由於Android和iOS的觸摸子系統不一樣,所以提出統一的API對整個React Native社區來講都是一個挑戰。可是,工做正在繼續進行,而react-native-gesture-handler只是達到1.0。
很長的list
React Native在這個領域取得了一些進展,包括像FlatList這樣的庫。然而,它們遠不及Android 上的RecyclerView或iOS 上的UICollectionView的成熟度和靈活性。因爲線程化,許多限制很難克服。沒法同步訪問適配器數據,所以能夠在快速滾動時異步呈現視圖時查看視圖。文本也沒法同步測量,所以iOS沒法使用預先計算的單元格高度進行某些優化。
React Native的升級
雖然大多數React Native升級都是微不足道的,但也有一些使人痛苦。特別是,幾乎不可能使用React Native 0.43(2017年4月)到0。49(2017年10月),由於它使用了React 16 alpha和beta。這是一個很是大的問題,由於大多數專爲Web使用而設計的React庫不支持預發佈的React版本。在這次升級中糾纏正確的依賴關係的過程對2017年中期其餘React Native基礎架構的工做形成了重大損害。
麻煩的崩潰
咱們不得不處理一些難以解決的很是奇怪的崩潰事件。例如,咱們目前正在經歷@ReactProp註釋的崩潰,而且沒法在任何設備上重現它,即便那些具備相同硬件和軟件的設備也會在野外崩潰。
Android上的進程中保存的實例狀態Android常常清理後臺進程,但讓他們有機會同步保存本身的狀態。可是,在React Native上,只能在js線程中訪問全部狀態,所以沒法同步完成。即便不是這種狀況,redux做爲狀態存儲也不兼容這種方法,由於它包含可序列化和非可序列化數據的混合,而且可能包含的數據超過了savedInstanceState包中可能致使崩潰的數據。生產。