Vue 用戶的 React 上手小結
這是一份從Vue用戶角度出發的React上手總結與對比。
構建系統
正常的前端工程化項目中,二者均採用Webpack/NPM作為模塊打包和依賴管理工具。
雖然不同腳手架所定製的Webpack配置有所區別,但實際上切換腳手架的難度可以說是最低的。
以至於
vue-springbud
(https://github.com/doodlewind/vue-springbud)
這個Vue腳手架可以構建配置一行不改,直接用於打包React項目(當然了,會缺失HMR與樣式預編譯等高級功能)。
React的生態更大而鬆散,體現在構建配置上,就是官方的loader更加專註JSX編譯,而不像vue-loader這樣既編譯模板,又預編譯樣式。
React的腳手架配置需要更多地定製樣式方面的配置,如css-loader/預處理器/CSS Module配置等。
不過在JS轉譯/Uglify/CommonChunk提取/ 全局變數/各類Assets loaders/開發環境Proxy等通用的Webpack功能使用上,二者的配置方式基本是一致的。
基礎 API 與功能實現
渲染數據
和Vue在HTML template內寫{}的形式不同,React將各種數據嵌套在JSX表達式中,然後render JSX到頁面上。
在渲染數組時,React中經常利用map將數據片段映射成一段JSX,然後在列表區域中直接引用map後的JSX變數來渲染數組數據。
而Vue中則使用類似Smarty語法的v-for指令來渲染數組。
同時,React需要為數據添加key來保證虛擬 DOM diff演算法的效率,而Vue中除非渲染的列表也是組件,否則一般不需提供類似用於優化的欄位。
渲染數據時另一種常見的需求是,將後端提供的數據進行一些簡單的轉換後再渲染至頁面上。在Vue中提供了組件的computed屬性來實現這一功能,而React中則需要在render函數中定義一個新變數,將轉換後的值賦給這個變數後render它。
更新數據
Vue和React組件內的this指向的都是組件的實例,它們都可以通過修改實例數據來更新頁面。區別在於,Vue中的this沒有提供state/props/setState API,不論是父組件傳入的數據還是子組件的數據,都在同一個this的作用域下(這樣業務代碼會更短一些)。
並且,Vue也沒有setState這樣的setter方法來更新數據,直接通過全量賦值this.xxx=yyy數據的方式就可以更新 DOM 了。
React和Vue的設計區別,在更新數據的API中可以得到體現。Vue的依賴追蹤Hack了對象的setter,因此在執行簡單的賦值操作時可以直接獲知狀態樹中的修改位置,但DOM更新是非同步的。因此在Vue中如下的代碼是沒有問題的:
需要顯式setState的React則不能從基礎的賦值操作中獲知變更內容,而是需要通過setState觸發一次render,而後在render中更新DOM狀態。因此這是一個容易踩的坑:
React中DOM狀態和數據狀態都是非同步更新的。Vue中僅DOM狀態非同步更新,需要保證DOM狀態正確更新時,所使用的Vue.nextTick()API實際上也類似於React的setState回調。
用戶輸入
與Vue中通過v-model綁定input等輸入元素的方式不同,React中在JSX里使用Input標籤時,需要顯式為表單的JSX提供一個onChange屬性,在此屬性中指定一個名稱形如handleInput的函數,在函數中調用React的this.setState()來更改狀態。
這個handler函數如果不在React組件實例中聲明,那麼則需要通過在constructor中添加this.handleXXX=handleXXX.bind(this)的方式來綁定函數中的this到React組件實例。
當存在多個input標籤時,React可以復用同一個handler函數,並在其中通過類似setState({ [name]: data })的語法糖來減少冗餘代碼(當然了這樣也比v-model要繁瑣一些)。
減少這些冗餘代碼的一種方式,是將基礎的輸入標籤(或標籤組)封裝為React的組件,並通過父子組件通信的方式來處理表單中用戶輸入狀態的更新。
事件傳遞
事件傳遞在Vue中是通過v-on和$emit來實現的。在父組件模板中聲明子組件時,通過v-on:childEventName="parentHandler"語法來指定對子組件特定名稱事件的Handler method。而遷移到React中後,其事件傳遞的機制有所區別。
另外,在React中常見組件ref屬性,可以使用這一屬性來在父組件中安全地調用子組件方法。而在Vue中雖然可以通過$ref獲取到子組件狀態,但這並不是一個推薦的做法。
狀態管理
React本身是一個純View庫,沒有狀態管理功能。因此在大型應用中需要Redux這樣的庫來做狀態管理。相應的概念在Vue中則是Vuex。二者所引入的新概念學習成本是相近的,從一種遷移到另一種也並不困難。
Vuex中,需要理解的核心概念是mutation和action。這兩種概念是從同步和非同步的角度出發去實現的。可以簡單理解為【同步狀態改變就commit一個mutation,非同步的狀態操作就dispatch一個action】。
在action中可以commit一個或多個mutation,也可以觸發其它Promise/async化的action來實現靈活的非同步控制流組合。
這個思維模式切換到Redux的reducer/action概念中,需要澄清的則是:
mutation和reducer並沒有什麼關係(不過它們確實都是同步的)。
Redux的action既可以同步,也可以非同步。
在最簡單的情景下,Redux中狀態的更改,首先需要dispatch一個action函數。
這個action函數會返回一個帶有type類型的原生JS對象,action觸發後,Redux根據action的類型去執行reducer中的邏輯,根據action返回的type以及相應的數據,決定如何更新全局狀態。
reducer中的邏輯是同步的純函數,並且可以通過combileReducers的API來組合多個子頁面的reducer,最後得到整個頁面的狀態樹處理邏輯。
在需要非同步的情景下,action可以不返回原生JS對象,而是返回thunk/promise一類用於非同步操作的數據類型,通過Redux的applyMiddleware API引入處理這些類型數據的能力。
例如redux-thunk就可以使得redux的action不局限於返回一個原生JS對象,而是返回一個【接收dispatch函數】的thunk函數。
這個函數在非同步操作成功時再去調用傳入的dispatch方法,在此提交一個真正觸發reducer邏輯的action。
Redux提供的subscribe API使得它能夠遷移到其它View庫中作為其狀態管理方案。
不過在React中,有react-redux這一中間層包裝了subscribe以及其它的Redux API,從而可以通過包裝根節點組件到Provider組件內,而後connnet組件到Redux的方式,簡化Redux在React項目中的使用。
由於action非同步情境下Redux沒有提供【官方且唯一】的處理方案,因此催生了redux-thunk/redux-promise/redux-saga/dva這樣種類繁多的輔助Middleware。
在這方面,React系確實有更高的可定製性,不過若需要一一了解它們並做技術選型,學習成本還是比引入Vuex要高的。
生態與工具
前文中已經提到了在狀態管理方面,React和Vue的一些異同。下面對比一些其它相關的周邊生態:
Devtools方面,React提供的Chrome開發插件和Vue的插件都對提升開發效率很有幫助。一些區別在於:
React插件支持將選中的組件映射到console的$r變數,更方便地實現調試。
React插件支持對生產環境的頁面進行調試。這在很多時候是很重要的。
React的插件不支持顯示【僅組件】的視圖,較難直接從 devtool視圖中選中想要調試的組件。
調試Redux時React插件沒有官方解決方案,而Vue的插件集成了Vuex的調試功能。
組件庫方面,目前React有相對更加豐富的組件庫,也有RN這樣的跨端解決方案。在Vue方面靠譜的組件庫除了Element UI外並不是很多。
在CSS預處理器支持方面,vue-loader提供了相對更完善的預處理器支持。
引入Sass/Less/Stylus只需指定.vue組件中style標籤中的lang屬性即可。
React的CSS Modules支持需要引入一些自定義的Webpack配置,相對定製性更強,也對boilerplate有更高的要求。
在第三方庫支持方面,二者都有不少封裝第三方庫的組件庫(當然了還是 React 更多)。
不過它們較Angular更為友好的地方在於,在React和Vue的組件中調用第三方庫都是較為方便的,不需要通過react-xxx或vue-xxx的封裝就能夠快速使用常見第三方庫(如圖表、ajax 等)的功能。
常見反模式
在接觸了中等規模(去除組件庫後,整個項目在約萬行級)的React業務代碼後,可以總結出一些常見的坑:
需要前端【更改一下數據格式】的數據一般都會通過map的形式轉換為JSX。但這些代碼經常直接就是放置在render函數中的局部變數,會降低render的可讀性。
未引入Redux時存在著多層組件間的事件傳遞,較為繁瑣。
React缺少原生的watch機制以訂閱某種數據的變更。
新手編寫的JSX頁面中容易混淆模板與UI邏輯,破壞數據和模板的分離解耦。並且JSX也容易變得冗長而不易維護,典型情況如【在JSX中嵌套三目運算符】。
constructor中可能存在大量的bind。
在組件方法中直接編寫各種ajax業務邏輯。
而相應地,在同等規模的Vue項目中也存在一些常見的坑:
未引入Vuex時存在多層的數據傳遞。
相對更簡單的語法造成新人加入時採用各種ES5語法(如使用ES6的函數而非箭頭函數、不用computed而在method中用古老的for循環拼湊數據並手動重置data屬性等)。
在組件中直接執行各種ajax業務邏輯。
類型檢查相對更松。如Vue在2.3之前HTML模板允許標籤不閉合,造成升級後一些模板編寫不嚴謹的頁面大規模報錯等。
總之,React最重要的組件化和狀態管理理念和Vue是一致的,熟悉Vue的開發者遷移過來並不需要很大的學習成本,更多考慮的還是團隊的已有積累和業務方向。
文章來源:
http://ewind.us/2017/vue-to-react/?utm_source=tuicool&utm_medium=referral
※10個JavaScript概念!Node.js程序員必須掌握
※ui 設計中的插畫與情感化設計
※快速學會SVN的搭建和使用
※大白話解釋 Git和GitHub
※AI取代人類前孩子的教育需要什麼改變?
TAG:優才學院 |
※Vue+VueRouter+elememntUI+axios 搭建後台管理系統
※Angular、React 當前,Vue.js 優劣幾何?
※教你使用Vue.js的DevTools來調試你的vue項目
※少女歌劇Revue Starlight-ReLIVE特別舞台
※《少女歌劇Revue Starlight》手游曝光
※Vue: scoped 樣式與 CSS Module 對比
※Vue中的methods、watch、computed的區別
※Vue.js 為何能逆襲 Angular 和 React 而主導前端?
※「少女歌劇Revue Starlight-ReLIVE」特別舞台報道
※GitHub趨勢:Vue.js大有超過TensorFlow之勢!
※PicGo—基於 electron-vue 的炫酷圖床工具
※「少女歌劇 Revue Starlight」公開同名手游新情報!
※簡單理解Vue中的nextTick
※《少女歌劇Revue Starlight》預約正式開啟
※前端圈小可愛Vue的自白:我年少成名卻又屢陷React、Angular混戰
※dotnet core webapi+vue 搭建前後端完全分離web架構(一)
※手把手教Vue-路由「Vue-rouer」
※Angular和Vue.js 深度對比
※React和Vue到底誰更牛?
※「少女歌劇 Revue Starlight」動畫完結,計劃發售紀念書籍