React Native 實踐與感悟

Starwars發表於2019-03-31

移動開發的發展漸漸趨於成熟,開發者的技能樹分佈漸漸完善。隨著大前端的發展跨平臺技術也衍生除了相關平臺。對於移動開發者來說,也是面臨著新的機遇與挑戰,各個公司也嘗試擁抱新技術,可以說這也是一個趨勢相關的挑戰。由於公司產品,存在Android,iOS兩組開發人員,且業務邏輯與UI幾無差別。對於成本和效率的考慮團隊開始考慮使用React Native 開發產品。

開始前準備

RN的開發語言基於ES6,整體框架基於React 實現。所以開發RN必須掌握 ES6和React,這兩者就不在此文討論範圍了。值得一說的是,之前開發android ,從17年google把kotlin提升到官方語言之後,就開始使用,其中一些語言與思想跟ES6相似,所以切換到ES6開發,還是很爽的。並且ES6有很多的語法糖,用起來甚是很6。跟ES5相比有增加了很多語法,對於java開發者來說熟悉很多,準守規範不至於入坑。如果使用TypeScript那就更熟悉了。React之前沒有接觸過,但是開發RN那是必須要熟悉的。看了看簡單的使用文件對於Component,Props,State,JSX都要有基本的熟悉,大概就可以開始使用了。

快速開始

能跑起一個'Hello World'大概是學習一項新技術開始。這是對環境以及相關基本的配置成功的一種標誌。怎麼開始呢?當然是找到官方文件,裡面有相關介紹。(多說一句,如果一項技術沒有完善文件,真的不值得使用)文件首選官網,那裡是有最新最詳細的介紹和使用。不過是英文的對於國內很多人來說,比如我也是很有障礙的。所幸有中文文章,雖然跟官方文件比起來,比較過時,很多沒有翻譯的到位。有些也確實,但對於我們的簡單開始是夠用的了。不得不說React Native中文網,的對於如何搭建開發環境是很詳細的,也考慮到了國內由於牆的存在產生的一些問題。照著文件來,並且保證自己可翻牆,沒有碰到什麼問題。通過 react-native init awesome project 生成第一個專案,然後react-native run-android 跑起來,成功的一刻當然是很開心的。不過還好,因為早早在15年rn剛開始出的時候我就已經試過了,不過那時候我才剛剛入行android。技術也不行,並且也沒有覺得RN能怎樣,學習成本對於我來說也高,畢竟android都還沒有整明白。也就沒有繼續下去,說起來還是自己拖延,執行力低,並且也沒有明確的規劃。後面RN也是發展的越來越成熟,但是國內應用的還是很少,到去年國外很多大公司開始宣佈棄用React Native,這又是另一個話題了。

React native 的能力

能跑起來'hello world'只是一小步,接下來還面臨著星辰大海。要想走得更遠我們就要確定RN的極限在哪兒。對於這一點就要弄清楚RN的原理,這一點對於現在的我來說,談這個有點不足夠。通過在Android上執行adb shell dumpsys activity top.檢視一個簡單頁面的原生堆疊。可以看到RN封裝了各個元件。就拿Image來說,最後顯示在Android上的是ReactImageView,又是繼承自DraweeView。所以傳遞給Image的屬性最終傳遞給了DraweeView了。這也就是React Native兩個單詞的含義了吧。

這如何傳遞,以及js,與native之間的雙向通訊暫且不討論。可以看到,通過這種對原生元件的封裝可以說RN能做到幾乎所有原生可以做到的。這裡可能會問,原生自定義View呢?這就是RN厲害的一點了,我們可以重用已經有的自定義View。通過RN的預留介面,只需要先定義好需要暴露的屬性,然後通過幾個步驟就可以實現在RN中呼叫自定義View了。這個能力真的是強。也許還會問,怎麼實現高效能程式碼呢,比如多執行緒?眾所周知,js是單執行緒模型,雖然ES6實現非同步也有好幾種方式,但是跟原生比相比還是差的。這之間的差距就涉及到我知識的盲區了。同樣的RN也提供了給我們介面實現,我們可以編寫原生程式碼,然後定義好介面,通過RN提供的介面暴露出去。就可以在RN中呼叫原生模組程式碼,同時由於通訊是雙向的,所以原生也可傳遞給RN。也就是幾乎不存在實現不了的情況。作為例子可以編寫一個Toast模組通過實現RN提供的介面封裝Toast,實現RN中呼叫我們自己實現的Toast元件,這個在官方文件上有完整demo存在。

但這個過程還是很繁瑣的,如果模組很複雜就要考慮到很多架構上的實現。這樣就對原生開發能力有一定要求,但這種需求畢竟是少數,並且到如今生態已經很完整,很多第三方庫,sdk等都退出了N版本,已經定義好了介面給RN呼叫。以上確定了RN與原生之間的互動補助了RN的短板。那麼RN本身可以在不依賴於原生的極限能力又有那些呢?前文提到,RN最後提供的都是原生元件。那麼RN能多大程度上不依賴於原生,僅僅通過自身實現各種互動效果呢,還有效能怎樣呢?九宮格顯示圖片,是非常常用的一個控制元件。通過對不同數量的圖片,在限制的區域內,佈局並動態的調整大小。在Android開發中,一般來說通過自定義ViewGroup,在onMeasure中實現調整演算法,並對每個子view進行測量。再在onLayout 在確定演算法,並且layout每一個子View到指定位置即可實現。當然最後還要考慮到載入圖片,以及定義屬性等問題。在RN中整體的思路是一致的只是很多步驟不再需要了。首先計算如何根據圖片數量調整佈局位置和每個Image的大小。拿到大小,Android中是把大小傳遞給ImageView#onMeasure,在RN中則指定style中的width,height.剩下的就是layout了。這一點有所不同,RN採用css標準佈局方式,支援flex佈局。所以我們是按照RN中定義的佈局方式佈局,這樣就可以了。剩下的圖片載入,則直接定義Image載入圖片的屬性就可以了。整個過程效率是很高的,並且是邏輯清晰的,最後執行的效果也不錯。通過這個例子可以知道RN實現普通的或者一些複雜的效果是完全可以的,效能上也能夠得到很好的解決。也許會說手勢,動畫對於RN來說怎麼樣,動畫對RN來說一直都是個影響效能很關鍵的一點,特別是在Android中。RN提供了相關的api來實現,因為我也沒有很深入的去測量具體效能怎樣,所以無法給出效能相關的結論。不過這些api常用功能還是實現的沒問題的,畢竟是對於原生功能的封裝。我想,通過以上的描述可以對RN做一個總結,對於普通業務場景中的開發RN是完全HOLD住的,對於需要高效能Native程式設計,Native也完全支援,對於Native已有元件RN也還是沒問題。所以RN能辦得到比我們想像得更多的事兒。

生態與框架

從2015年RN開源到如今,已經走過了四個年頭。隨著社群中開發者不斷的努力,現在的RN早已不是當初一堆坑的RN了。在我面前的是成熟,煥發著無限能力的RN。這一切都離不開RN的整個生態和第三庫。開啟github的 awesome-react-native,可以看到翻不到底的專案。這些專案都是開發者的努力,也是我們可以使用並借鑑的。正式由於這些專案,RN才可以達到現有的成熟和效率。對於一個應用來說,路由始終是一個繞不過去的關鍵問題。在web中,很簡單,僅僅通過<a/>標籤的href屬性就可以實現跳轉。Android中通過Intent也很簡單。但是在RN中情況就複雜很多了,早期並沒有很好的解決方案,通過社群的努力 React-Navigation誕生了。現在已經到3.x版本。可以很方便的實現頁面之間的路由。像這樣幫助開發的開源專案還有很多例如Redux等。共同支撐起來RN的生態。

專案實戰

在實踐中學習,我一直認為是掌握一門技術的最好方式。在學習中我也實現了一個gank.io的RN版本。總得來說在這個過程中把各個RN中的知識點都過了一遍,也形成了一套開發套路,也對RN專案的理解更深了。RN基於狀態管理,這一點對於開發業務來說還是很方便的。規劃好了狀態,業務邏輯清晰基本的實現基本沒有問題。如果專案大起來,狀態的管理會導致效率的降低,這時候通過Redux是很必要的。對於元件的狀態封裝一個下拉重新整理上拉載入的元件,是一個很好的例子。這個元件需要有 正在重新整理,可以載入,錯誤,載入完成等狀態,實現的細節不再此文。不同的狀態展示不同的UI真的是很容易。react-navigation 雖然功能強大,但我用著還是不爽,可能是還沒有用熟悉吧。專案的架構,參考了github上成熟的開源專案,這一點跟android專案其實沒差,大概可以按照相同的方式組織程式碼。不過原則還是要與一個統一的規範。剩下的就是業務邏輯了,這也是一個程式的內容和功能所在。業務邏輯其實是沒多大差別,只要想好了實現步驟。不過具體的實現肯定是有差的。在RN中,就很爽fetch函式返回的Promise物件那可是方便。而且通過State狀態管理,很方便的切換各個狀態,再借助生態中提供的一些庫,可以說只要不是太複雜的業務。實現起來難度並不高。總體而言實現一個展示類的App用RN真的爽。如果細節一些我想需要考慮的問題還會比較多,比如對Android中機型的適配,如何編寫高效能的程式碼,效能管理等。

參考資料

官方文件

awesome react native

相關文章