指尖前端重構(React)技術調研分析

宜信技術學院發表於2019-09-26

重構前的技術文件調研與分析,包括技術選型為什麼選擇react,應用過程中的注意事項等。

一、為什麼選擇React

React是當前前端應用最廣泛的框架。三大SPA框架 Angular、React、Vue比較。

  • Angular出現最早,但其在原理上並沒有React創新的效能優化,且自身相對來說顯得笨重。
  • Vue出現最晚,其核心原理學習了React,只是語法形式的變化,關係上來說React是開拓者,Vue是學習者。
  • React社群有強大活力與創新能力,不斷湧現革命性的創新產品,其中包括可以使用JS操作原生控制元件的React Native,Vue後來跟進學習出了類似的Weex,但兩者成熟度差很多。

目前來看React的生態系統要比Vue大的多,在github、stackoverflow等最大的技術社群搜尋兩者,React的搜尋結果是Vue的十倍左右,另外據近期統計使用React的站點是Vue的幾百倍以上。更大的生態意味著更多可用的資源,以及遇到問題可以得到更多的有效參考與幫助,這也是除了效能之外選擇React的核心原因。

選擇React之後,應用會在以下幾個方面有提升。

  • 第一,原先的html間跳轉會有短暫的白屏現象,這一點在安卓效能較差的機器上尤為明顯,而React作為單頁應用沒有這個問題。
  • 第二,React 提供的虛擬DOM包含Diff演算法,即將原dom copy一份,與改動後的dom對比,只渲染不同的dom節點,實現最小代價渲染,vdom創新的效能優化方式對效能的提升毋庸置疑。
  • 第三,React中核心元件化技術,更加容易的繫結事件行為,動態更新特定的dom,程式碼更加模組化,重用程式碼更容易,結構清晰易維護。

二、在移動端使用React

三大框架在移動端分別有自己的東西。Angular的ionic,React的React Native,Vue的Weex。其中ionic 是基於cordova技術,依然是瀏覽器應用。而後兩者已上升到操作原生控制元件的層面,做出來的是原生介面,其中React Native的成熟度遠高於Weex,已經被很多公司使用,而Weex使用者很少。

綜合來看選擇React 生態明顯最佳,由當前的cordova過渡為cordova+Reactjs,然後可以平滑地過渡到React Native,媲美原生效能的最優混合開發方式。之所以說平滑是因為React Native中近90%的程式碼(JS)可以在IOS和Android端使用,剩餘的涉及原生的程式碼也基本可以找到可用的資源,就像cordova 的外掛一樣。畢竟如果需要同時掌握JS, OC(或swift),java(或kotlin)才能開發React Native的話,那這門技術不會有人用;當然反過來如果有原生開發知識的話會對開發React Native有一定幫助。

直接轉型為React native的話涉及了應用底層架構的變動,有比較大的跨度,而轉為cordova+Reactjs相對容易,而由cordova+Reactjs到React Native同樣容易不少,因為其中大部分Reactjs程式碼可以重用。

三、Reactjs開發工具的選擇

首先開發腳手架官方出了Create-react-app,整合了webpack-當前最流行的打包工具,babel-提高js版本相容性的轉碼器,以及ESLint-程式碼檢測工具和其它一些常用工具,同時對這些工具進行了比較優的配置。值得一提的是該腳手架將這些工具的配置檔案進行了隱藏,本意是讓使用者專注於編碼即可,但實際使用時通常會有自己配置的需求,此時執行npm run eject即可出現被隱藏配置檔案。

React-router 是官方推薦的路由管理工具,由於是單頁應用區別於原先的html介面間跳轉,跳轉實質是在元件間進行,所以需要有路由管理工具來統一化管理。這裡值得一提的是,React-router配合webpack可以實現程式碼的按需載入。

一般來說,webpack打包後會在生成一個壓縮的js檔案,在單頁應用開啟會整體載入這個檔案,由於該js檔案包含之前所有的js程式碼,雖然進行了壓縮,一般仍至少有幾百kb,當應用稍微複雜點,打包後檔案會相應變大。而載入的時候,不管那些程式碼有沒有執行到,都會下載下來並進行載入,造成效能浪費,這一點在顯然在web端很重要,而在cordova中是將js程式碼直接打包在本地,等於跳過了下載步驟但仍然會有載入過程。通過在router中寫require.ensure程式碼並在webpack中相應地修改配置即可將js分成多個檔案,在需要時載入對應的js檔案,實現按需載入。

Redux 是應用最廣泛的第三方狀態管理工具,其作用是當應用中多資料狀態互動時,可以更有方便且程式碼結構清晰地統一管理狀態,下圖給出了形象的闡釋。由於在實際開發中一般是分人員/分功能模組獨立開發,考慮引入redux的成本(redux本身略複雜),可以在沒有多資料互動的模組不使用redux,而在類似涉及增刪改查的表單以及即時通訊websocket等契合redux的模組使用。

為專案選取合適UI元件庫,一定程度上簡化UI樣式的開發並且考慮使用其提供的過渡動畫效果。這方面有比較多的選擇,Google Material Design 風格的Material-UI在github上最受歡迎,但其設計語言與我們當前APP截然不同,騰訊的weui和阿里的antd-mobile 較為相近,其中antd-mobile與create-react-app腳手架配合使用時配置項比較繁雜,因為阿里本意是用來配合自己的腳手架dva(封裝了react-router和redux),因此暫時選擇weui,後期開發有特定元件需求可結合其他ui庫使用。

至於頁面跳轉時的過渡動畫,有些UI庫給出了一些過渡樣式,比如touchstone。但該庫已不再維護,文件不佳,且與新版本的react-router配合使用有不相容情況。後來瀏覽官方文件發現官方有動畫庫react-addons-css-transition-group,使用該庫結合css3的動畫三件套animation,transition,transform即可實現各種動畫效果包括基本的過渡效果,比如漸進平移等。

另外關於css,因為是單頁應用,所以如果不加處理,直接import css檔案的話最終打包生成一個css檔案會導致樣式應用到全域性,造成同類名樣式相互汙染影響。解決這個問題有很多種方案。Facebook積極探索css in js方式,但直接寫內聯樣式程式碼可讀性太差。目前解決方案中應用最廣泛的是css-modules,即在webpack配置中開啟module選項,使用styles物件來寫樣式。

解決的原理是將css類名在打包後編譯成雜湊字串,保持其唯一性。但當想要使用全域性樣式時要再配置,稍顯繁雜,且它類名編寫的方式為物件的方式,需要整體修改,另外在使用它時,發現不支援-橫線的類命名方式,支援下劃線方式,推薦駝峰式,而我們之前html中的樣式類名大多是橫線命名,這意味著原html和css中的類名都要對應修改,考慮到樣式類名非常多,這一方式捨棄。

另外有基於css-modules使用高階元件的react-css-modules使用人數也比較多,允許橫線命名方式且全域性本地樣式區分簡單,但有benchmark測試表明其會較大程度拖累效能,所以也捨棄。解決這個問題要最大程度相容原先css的寫法,即改動最小,因為之前的css類樣式數量龐大。

Webpack css-loader 有個屬性 :local 加上之後類會變成區域性作用域,即webpack會對該型別的類進行自動雜湊轉碼處理,但顯然類名一個個加:local 是有些呆板的工作,於是想到可以利用scss的巢狀屬性將:local在一個css檔案中統一加到類名前。這裡涉及到在腳手架create-react-app 新增對scss的支援,在命令列執行安裝,並在package.json的scripts中新增watch-css指令,將原css檔案改為scss檔案,然後在最外層新增:local,執行watch-css命令,即可在scss檔案旁自動產生css檔案,且類名前自動新增:local 字首,這種方法實踐中發現並非所有類的樣式都與:local 相容良好,相應的可以使用檔名代替:local,要做的就是保持檔名的唯一性,這一點原工程下的檔名已滿足。這樣原先檔案中引入css的方式,全域性css引入的方式都不需要變化,做到最小代價。

scss 是 sass 3 引入新的語法,其語法完全相容 css3,並且繼承了 sass 的強大功能,sass和less是前端擴充css常用的方式,新增了巢狀,變數,繼承等語法,但需要編譯成css來最終使用(穩定性考慮)。

四、Reactjs 和cordova結合有哪些需要注意的

開發Reactjs使用官方提供的腳手架Create-react-app,最終通過npm run build生成一個單頁網頁應用,放入cordova的www目錄下即可。由於這兩部分開發時獨立,而原先開發是在含www目錄的cordova工程目錄下直接開發,這種不同會產生一些問題。比如cordova中某些外掛安裝後export函式或者變數供引入使用,因為一開始是分離的,在create-react-app中並找不到這些變數,就造成在build的時候產生變數undefined的錯誤,儘管最終放到cordova工程中後可以找到變數並正常執行,但在第一步react開發時控制檯報一堆error會妨礙除錯,影響開發體驗。

在github上有一些react cordova 庫,但實質上它們都需要通過npm run build來打包,所以並沒有解決引入外掛變數的問題,且會與create-react-app 有相斥的地方。所以要想辦法使外掛提供的變數在React中不報錯,這裡在不影響ESLint 檢錯機制的情況下可以採取迂迴的方式。Build時控制檯報錯僅針對src資料夾下的程式碼,而在public資料夾下還有個index.html這個檔案會最終被打包放到www目錄下,因此可以在這個檔案中deviceready時新增全域性的外掛變數(注意該類全域性變數的唯一性,可以新增plugin字首或使用名稱空間等方式保證),並將值傳給src目錄下的程式碼中,這樣即可繞過控制檯build以及除錯時的報錯。

另外一個小技巧可以將react工程直接放在cordova工程目錄下,指定最終build生成的檔案放入www目錄下,省掉手動轉移檔案的過程。

還有需要注意的一點是由於React中預設配置的公共路徑是絕對路徑,當放在cordova中時需要使用file協議放本地,需要在webpack的production配置的public路徑前加".",或者在package.json 檔案增加一行"homepage": "../www"或"homepage": "."改為相對路徑,否則會出現找不到檔案的情況,這裡推薦最後一種方式。

五、React專案的目錄結構

首先IDE選取webstorm,功能強大,之前專案組在用可以沿用下來,但需要注意的一點是當目錄中包含了安裝的依賴node_modules時,由於該資料夾下檔案數量非常多,webstorm在智慧建立程式碼關聯時會佔用大量資源,在某些電腦上會偶爾會出現卡死現象,這一現象在我配置比較高(固態硬碟加8g運存)的電腦上同樣出現了,解決辦法是在file-setting-File types中配置ignore node_modules 資料夾。

上圖是create-react-app 專案的目錄,主要程式碼放在src目錄下。Components中包含所有元件。React嚴格地執行元件技術,元件化不僅方便重用,同樣可以將一個頁面清晰地分割為幾個部分最後放入一個父元件展示,因為jsx技術將js和html放在了一起,分割後每個部分有自己的功能邏輯與頁面展示,這樣更加清晰易維護。事實上react提出了一切皆元件的思想,只是有的元件render了部分介面,而有的沒有render。

上圖中components下有common檔案用來放專案成員自己寫的公用元件比如公共請求方法等,external放外部引入的元件,work_log裡放的是我寫的工作日誌模組的元件,各個功能模組都各自建立一個資料夾,命名規則統一使用下劃線方式,這也是之前使用的方式。具體功能模組的劃分與層級關係可以參考之前的.

值得一提的,以前html的層級關係必須嚴格為兩層(涉及到跳轉路徑的邏輯),導致最後出現沒有把一個功能模組放到一個資料夾裡的情況,比如上面的工作日誌之前所包含的各個檔案直接和其它的一些功能模組一起放到了setting資料夾內。而現在只要在React-router統一配置好路由,實質上是往某個元件跳轉,不存在跳轉路徑的限制。

Constants資料夾下存放各種常量,比如各種介面路徑。Fonts存放字型圖示檔案,images存放圖片,redux資料夾下是redux的幾個組成部分,styles下放scss/css樣式檔案。Index.js是入口也是最頂層的父元件,router.js則維護了整個應用的路由關係。

上面就是本次調研的技術分析文件,瀏覽大量技術文件,開源社群以及技術論壇並結合實踐摸索得出的選型思路和理由,可能依然會有一些點沒有新增進去,以後會結合新知識和實踐繼續完善。

作者:樑鑫

來源:宜信技術學院


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69918724/viewspace-2658296/,如需轉載,請註明出處,否則將追究法律責任。

相關文章