本文來自作者 Yeh. 在 GitChat 上精彩分享, 「閱讀原文」看看大家與作者交流了哪些問題
【不要錯過文末彩蛋】
編輯 | 汶澤
引言要了解 React 的思想,還得從下面這張圖說起。
The State-Action-Model (SAM) Pattern
話說2016年2月的一篇文章 no-more-mvc-frameworks 描述了一種新的函數式、響應式模型,而它的思想來源正是來自 React 和 TLA+,這一模型就叫做 SAM 模型。
SAM 模型讓前端開發人員更專注於從模型中去建立視圖,而不會受牽制於基礎 API。
因此 SAM 完全符合軟體架構的重要設計原則。這種模型的最佳實踐莫過於 React 與 Angular 了,隨著他們的發展,前端架構思想開始了轉變。
雖然 React 官網將 React 定位為創建用戶界面的JS庫,但我想說的是,「React is just the View in MVC」這一說法太過委婉了。
React 所帶來的是整個前端技術棧的進化,各種函數響應式框架逐漸在完善。隨著 React 的發展和流行,圍繞著 React 的生態系統已經逐漸形成。
而從 React 小白到大神,必須要經歷三個境界,但總歸起來就五個字:「就解問題嘛」——出自「阿里掃地僧」多隆。
因此,本文通過描述每個知識點解決了哪些問題的方式來為大家介紹 React生態系統。
一、React龐大的體系1.1 ReactJSReactJS 到底解決了哪些問題呢?先來一份總結的 ReactJS 特點:
高效:React 通過虛擬 DOM 和 Diff 算法,最大限度地減少與DOM的交互和渲染。——提高運行效率
組件化:通過 React 構建組件,使得代碼更加容易復用,適應大型項目開發。——提高可維護性和復用性以及開發效率
模塊化:通過模塊化工具庫來解決模塊化問題——提高可維護性和復用性
單向數據流:React 實現了單向響應的數據流,從而減少了重複代碼,這也是它為什麼比傳統數據綁定更簡單。提高可維護性。
一言以蔽之,ReactJS 解決了前端技術規劃中應該考慮的這幾件事:組件化、模塊化、開發效率、運行效率、可維護性…
1.2 React生命周期下圖很直觀地描述了 React 生命周期的整個過程:
React生命周期
這裡有個不錯的 github 項目:react-pxq。這是的一個 react + redux 項目,其中滲透出了作者(bailicangdu)對 react 的理解,能很好的幫助大家快速上手 react。
生命周期這東西說簡單也簡單,說難也難。有的人說,不就是幾個階段嗎?
但如果你是去面試,有經驗的面試官可能會出這樣幾道題:
React 在初始化和更新的時候會觸發的鉤子函數?
父組件在更新狀態的時候父組件與子組件的生命周期順序是怎麼執行的?
針對第1個問題,就算不懂的人看幾眼背一下都能答出來。而第2個問題就比較考驗你的知識深度了。
首先需要知道子組件在什麼時候會被渲染?它一定會被渲染嗎?有什麼方法能夠減少它的渲染?一大堆引申的知識點,如果能應對如流(最好的方法是看源碼咯),相信你會給面試官留下好印象。
1.3 React RouterReact Router 是 React 中使用的路由庫,通過管理URL來管理組件及對應的狀態。
Router 組件本身只是一個容器,真正的路由要通過 Route 組件定義。
Router 組件支持嵌套路由、支持通配符,能讓你輕鬆控制整個項目的路由結構。
1.4 ReduxRedux 跟 React 沒有直接的關係,本身可以支持 React、Angular、Ember等等框架。Redux 其實是 Flux-like 更優雅的寫法,下圖對比了Flux與Redux的數據流向:
Flux與Redux的數據流向
通過 react-redux 這個庫,可以方便的將 react 和 redux 結合起來:React負責頁面展現,Redux 負責維護/更新數據狀態。
大致過程為:當用戶在 View 中觸發事件產生 Action,Action 進到 Reducer,Reducer 根據 Action Type 去匹配對應處理的動作,然後返回一個新的狀態。
View 則因為檢測到狀態更新而進行重繪。Redux 只有一個 Store 負責存放整個 App 的狀態,而唯一能改變狀態的方法只有發送 Action。
Redux 社區中使用比較多的庫有:redux-sagas、redux-gen、redux-loop、redux-effects、redux-side-effects、redux-thunks、rx-redux、redux-rx…
1.5 React測試目前廣大開發者偏向使用 Airbnb 團隊開發的 enzyme,它也可以與其他測試工具如 Jest、Mocha 等配合使用。
比如我們使用 jest-enzyme,由於Jest是 Facebook 開發並且是在 Jasmine 測試框架上演變而來的,斷言格式我們比較熟悉,因此大家可能更容易上手。
Jest 的目標是減少測試一個項目所要花費的時間和認知負荷,它提供了大部分我們需要的現成工具:快速的命令行接口、Mock 工具集以及它的自動模塊 Mock 系統,總的來說就是讓測試變得更簡單。
1.6 React NativeRN 是在 Facebook 所提出的核心概念 Learn once, write anywhere 所誕生的產物,著力於提高多平臺開發的開發效率。
我們可以同時為 android 和 ios 兩個平臺開發 App,只需要根據兩個平臺不一樣的地方去做一些調整即可。
RN 主要負責 UI 部分,而原生主要負責交互和數據處理。RN 屬於 hybrid 開發,並且與原生無縫連接,相比 Web App 和 Native 開發,RN取長補短,集合了兩者的優勢。
RN 開發的 APP 可以跳過 App Store 審核,遠程更新代碼,提高迭代頻率和效率,既有 Native 的體驗,又保留 React 的開發效率。
RN 的原理是將 React 代碼轉化為原生 API,iOS 一套,Android 一套。RN在一開始生成OC模塊表,然後把這個模塊表傳入JS中,JS參照模塊表,就能間接調用OC的代碼。
相當於買了一個產品(OC),對應一份說明書(模塊表),用戶(JS)參照說明書去操作這個產品。
如何學習RN呢?可以跟著 git 上的 awesome 系列去進階。從源碼角度看RN,主要需要了解RN如何做到JS和OC交互、RN的啟動流程是怎樣的、如何加載 JS 源碼、UI 控制項的渲染流程、事件處理流程以及 RN 與 iOS 之間的通信方式等。
做 React 還需要懂什麼?
1.7 NodeNode 打破了過去JS只能在瀏覽器中運行的局面。前後端編程環境的統一,大大降低了前後端轉換所需要的上下文交換代價。
Node 就是瀏覽器在協議棧另一邊的倒影,雖然不處理UI,卻與瀏覽器有著相同的機制和運行原理。其高性能並行 I/O 使得分布式開發更加高效,利用穩定接口可提升 web 渲染速度,也十分適合做實時應用開發。
第2部分將闡述 Node 在前後端中的角色作用。
1.8 NPM與Yarn我們知道 Node 的包描述文件是一個 JSON 文件,用於描述非代碼相關的信息。而 NPM 則是一個根據包規範來提供 Node 服務的 Node 包管理器。它解決了依賴包安裝的問題,卻面臨著兩個新的問題:
安裝的時候無法保證速度和一致性。
安全問題,因為NPM安裝時允許運行代碼。
於是 Yarn 就出現了,不要慌,它並沒有試圖完全取 NPM,不過 Yarn 確實也是可以完美替代 npm 的。
1.9 模塊化開發隨著 web 應用的發展,前端的業務邏輯越來越複雜,代碼也越來越多,各種問題就暴露出來了:全局變量汙染、函數命名衝突、依賴關係混亂等問題嚴重阻礙了前端開發的發展,JS模塊化勢在必行。通過開發者不斷地嘗試,出現了各種規範和實踐:
CommonJS
Node.JS 首先採用了js模塊化的概念。Node.js 伺服器端通過 exports、module.exports 來輸出模塊,並使用 require 同步載入模塊,而瀏覽器端的可以使用 Browserify 實現。
AMD
AMD規範用於異步加載模塊,主要用於瀏覽器端,當然也支持其他js環境,主要應用有requireJS。
ES6 Module
ES6 標準定義了JS的模塊化方式,目的是取代 CommonJS、AMD、CMD 等規範,一統江湖,成為通用的模塊化解決方案。
但瀏覽器和Node端對ES6的支持度還不是很高,需要用 Babel 進行轉譯(Babel編譯器可以將ES6、JSX等代碼轉換成瀏覽器可以看得懂的語法)。
Gulp/Grunt+Webpack/Browserify
在構建前端項目資源,使用自動化工具協助進行自動化程序碼打包、轉譯等重複性工作,可以大幅提升開發效率。
Gulp
Gulp和Grunt一樣是一種基於任務的構建工具,能夠優化前端工作流程。
Webpack
webpack 傻瓜式的項目構建方式解決了模塊化開發和靜態文件處理兩大問題。但隨著項目越來越大,特定需求的出現就使得 webpack 越來越難配置了。
因此 webpack 在沒太多特定需求的項目使用是沒有問題的,當然,webpack 的未來肯定是圍繞ES的支持度、構建速度與產出代碼的性能和用戶體驗來建設的。其未來的重要關注點:
高性能的構建緩存
提升初始化速度和增量構建效率
更好的支持Type Script
修訂長期緩存
支持WASM模塊支持
提升用戶體驗
Browserify
Browserify是基於Unix小工具協作的方式實現模塊化方案的,輕便且配置容易,管道形式的組織則讓開發者很容易插拔或修改其中某一環節的操作。
至於怎麼配合使用,我覺得仁者見仁智者見智,確實是不好下定論,只有親身體驗才能擇更好者而用吧。
ES2015/ES6
我們都知道ECMASCRIPT是組成JS的三要素之一,ES6其第6個版本,ES的歷史確實也挺曲折的。通過ES6最常用的特性,我們來了解ES6到底解決了什麼:
let, const(變量類型):解決變量作用域洩露的問題。
Class, extends, super(類、繼承):讓對象原型的寫法更加清晰、更像面向對象編程的語法,也更加通俗易懂。
Arrow functions(箭頭函數):1.簡潔、簡潔、簡潔,2.解決this綁定的問題(繼承外面的this)。
Template string(模板字符串):解決傳統寫法非常麻煩的問題。
Destructuring(解構):避免讓API使用者記住多個參數的使用順序。
Default, rest(默認值、參數):簡化,替代arguments,使代碼更易於閱讀。
ImmutableJS
我們知道在 JavaScript 中有兩種數據類型:基礎數據類型和引用類型。在 JavaScript 中的對象數據是可以變的,由於使用了引用,所以修改了複製的值也會相應地修改原始值。
通常我們用 deepCopy 來避免修改,但這樣做法會產生資源浪費。而 ImmutableJS 的出現很好的解決了這一問題。
React的生態系統還有噓噓多多相關的知識,本文並不能全面涵蓋所有知識,望諒解。
另外,推薦大家從 git 上的 awesome 系列去學習你想要學習的一門知識。
如果是有英文而沒有中文,大家也可以fork下來去做一些翻譯,為大前端技術做做貢獻嘛!:-D
二、前後端架構分離前後端分離的分層架構圖
很多人都有過 MVC 架構的開發經驗,從 Spring MVC 開始,寫JSP,再到使用 freemarker,然後再到狹義的前後端分離,也就是 Web 端通過ajax調用接口,使用JS把數據渲染到頁面上。
以前後端人員套頁面,數據結構和業務邏輯混淆在一起,項目越來越大後,維護起來特別的繁瑣。
目前看到的前後端分離項目都是上圖所示這種形式去實現的。尤其是在大公司,基本都是採用面向服務架構的開發模式,團隊開發中的溝通成本以及職責明確特別重要。
而前後端分離的意義主要在於解耦,解耦後前後端職責劃分更明確,前端能做的事也越來越多。
比如我們可以在 Node 層做些監控和日誌管理,將 SSO 登錄集成進 Node 層,使用 PM2 對 Node 做多進程管理。這樣之後,後端項目就可以做成」微服務」式的架構。
從前端項目工程化管理的角度來看,後端項目」微服務」式架構有如下優勢:
前端只與 Node 中間層進行數據通信,Node 層則通過 thrift 接口與後端服務進行數據通信;Node 中間層的 API 設計遵循 RESTFul 的架構風格,並且都以 /api/* 做為前綴;Node 中間層可以視情況添加緩存服務
三、前端工程化現代化的前端開發已經不僅僅是業務代碼本身,而是涉及了很多方面的需求,比如:開發需求、共享需求、性能需求、部署需求。
3.1 開發需求如果是新團隊,在開始一個前端項目時,我們會先進行技術選型,然後定義代碼規範,再根據業務模塊拆分進行項目目錄規劃,這些相關的需求都算作前端開發需求。
如果在成熟團隊中,可能已經有技術沉澱了,怎麼去優化和改進以及文檔化就成為我們需要去琢磨的事了。
代碼規範
ESLint是一個用來識別 ECMAScript 並且按照規則給出報告的代碼檢測工具,使用它可以避免低級錯誤和統一代碼的風格。
我們可以方便的在配置文件中配置自己想要的風格規範,通常推薦使用Airbnb JavaScript或者google的規範。
CSS預處理
我們可以使用 less 或 sass 來優化 css 的開發過程,而如果考慮到瀏覽器兼容性的hack問題,我們可以用 postcss 作為預處理工具幫我們自動解決這些 hack。
熱更新
hmr能夠在感知你的代碼有變動的情況下自動調用編譯工具編譯源碼,然後通過 livereload 自動刷新瀏覽器,這樣做的話能節省你的調試時間。
Mock
由於採用了前後端分離的開發模式,在真實開發中,為了讓前端開發不受後端進度的影響,我們需要對數據進行 mock。
前後端先約定 API 接口定義,然後前端根據定義 mock 接口。
一般大公司會有自己的 mock 平臺,小公司如果沒有的話也可以使用開源的mock工具。
3.2 共享需求對於公司而言,快速高效地實現業務是終極目標,這對前後端來說都是挑戰。在前端團隊中,能夠形成基礎組件庫和業務組件庫是一種必然需求。
所以在設計前端項目架構的時候,一定要考慮業務的組件化和可共享性。有人說開發通用組件是造輪子,其實造出符合自己的輪子何嘗不是一種領悟。
共享需求主要有四種:基礎代碼共享、通用工具方法共享、基礎交互組件共享以及業務組件共享。
在組件方面,React 提供了天然的組件結構,我們只需要在開發過程中,隱藏組件的內部實現,每個組件更獨立,很容易形成可重用組件。
3.3 性能需求如何對 web 資源的加載速度進行優化呢?
JS/CSS 代碼壓縮
JS/CSS 代碼合併
圖片壓縮
CSS 圖片精靈或雪碧圖
這些過程都可以在前端工程的構建過程中使用 Grunt/Gulp、webpack 等構建工具實現。
3.4 部署需求前端工程通常是由多人維護的,所以會用代碼管理工具來管理源碼,然後將開發流程和部署流程與 git 結合起來。多人分支協作流程:用 git flow 來管理代碼分支。
四、總結實踐證明,圍繞著 React 所建立起來的生態系統以及組件化開發思想能有效地分解大規模應用的複雜度、提高資源復用率。簡單的說,React 擁有以下你想要的特性:
當然,使用React也有一些缺點,例如頁面 javascript 文件體積動輒上百KB,這就限制了在移動端項目上的使用。
我們可以通過一些離線化方案,例如使用 LocalStorage 緩存等來儘量的減少對大體積靜態資源的請求。
總的來說,React 的生態系統大而全,如果沒有涵蓋的部分,還請海涵。僅此與各位 dalao 共享一些個人觀點,共同進步。
彩蛋
重磅 Chat
《一場 Chat 讓你搞清 BAT 程式設計師的技術職級》
分享人:
勝洪宇,一線網際網路公司前端技術組長,掘金籤約作者,前端博客博主,所講課程幫助超過20萬前端小夥伴學習。
Chat簡介:
很多程式設計師嚮往進入 BAT 這樣的大型網際網路公司,但是又不知道他們如何評定技術職級。
阿里集團薪資職級如何劃分?讓你快速得到馬雲的青睞。
在百度明白這些,你將快速晉升。
騰訊職級裡的小秘密,這樣工作你會更強。
一場 Chat 讓你搞清 BAT 的技術評價體系,為您進入超級網際網路公司指明技術方向,時刻做好準備!如果您希望您的技術團隊也像這些網際網路巨頭一樣強大,本場 Chat 我將幫您馬上模仿建立有效的技術職級體系。
想要免費參與本場 Chat ?
關注「GitChat 技術雜談」公眾號
並在後臺回復「BAT」
👇
「閱讀原文」查看 本次Chat交流實錄