這篇文章記錄我在使用Vue和React的時候懦傍,對他們的不同之處的一些思考。
不僅局限于他們本身答渔,也會包括比如 Vuex/Redux 等經(jīng)常搭配使用的工具灌侣。
因為涉及到的內(nèi)容很多,可能下面的每一個點都能寫成一篇文章焊唬,這次先簡單做一個概要恋昼,等我有空做一個詳細的專題出來看靠。
監(jiān)聽數(shù)據(jù)變化的實現(xiàn)原理不同
Vue 通過 getter/setter 以及一些函數(shù)的劫持赶促,能精確知道數(shù)據(jù)變化,不需要特別的優(yōu)化就能達到很好的性能
React 默認是通過比較引用的方式進行的挟炬,如果不優(yōu)化(PureComponent/shouldComponentUpdate)可能導致大量不必要的VDOM的重新渲染
為什么 React 不精確監(jiān)聽數(shù)據(jù)變化呢鸥滨?
這是因為 Vue 和 React 設計理念上的區(qū)別,Vue 使用的是可變數(shù)據(jù)谤祖,而React更強調(diào)數(shù)據(jù)的不可變婿滓。
所以應該說沒有好壞之分,Vue更加簡單粥喜,而React構建大型應用的時候更加魯棒凸主。
因為一般都會用一個數(shù)據(jù)層的框架比如 Vuex 和 Redux,所以這部分不作過多解釋额湘,在最后的 vuex 和 redux的區(qū)別 中也會講到卿吐。
數(shù)據(jù)流的不同
大家都知道Vue中默認是支持雙向綁定的
在Vue1.0中我們可以實現(xiàn)兩種雙向綁定:
父子組件之間旁舰,props 可以雙向綁定
組件與DOM之間可以通過 v-model 雙向綁定
在 Vue2.x 中去掉了第一種,也就是父子組件之間不能雙向綁定了(但是提供了一個語法糖自動幫你通過事件的方式修改)嗡官,并且 Vue2.x 已經(jīng)不鼓勵組件對自己的 props 進行任何修改了箭窜。
所以現(xiàn)在我們只有 組件 <--> DOM 之間的雙向綁定這一種。
然而 React 從誕生之初就不支持雙向綁定衍腥,React一直提倡的是單向數(shù)據(jù)流磺樱,他稱之為 onChange/setState()模式。
不過由于我們一般都會用 Vuex 以及 Redux 等單向數(shù)據(jù)流的狀態(tài)管理框架婆咸,因此很多時候我們感受不到這一點的區(qū)別了竹捉。
HoC 和 mixins
在 Vue 中我們組合不同功能的方式是通過 mixin,而在React中我們通過 HoC (高階組件)尚骄。
React 最早也是使用 mixins 的活孩,不過后來他們覺得這種方式對組件侵入太強會導致很多問題,就棄用了 mixinx 轉而使用 HoC乖仇,關于mixin究竟哪里不好憾儒,可以參考React官方的這篇文章 Mixins Considered Harmful
而 Vue 一直是使用 mixin 來實現(xiàn)的。
為什么 Vue 不采用 HoC 的方式來實現(xiàn)呢乃沙?
高階組件本質(zhì)就是高階函數(shù)起趾,React 的組件是一個純粹的函數(shù),所以高階函數(shù)對React來說非常簡單警儒。
但是Vue就不行了训裆,Vue中組件是一個被包裝的函數(shù),并不簡單的就是我們定義組件的時候傳入的對象或者函數(shù)蜀铲。
比如我們定義的模板怎么被編譯的边琉?
比如聲明的props怎么接收到的?
這些都是vue創(chuàng)建組件實例的時候隱式干的事记劝。
由于vue默默幫我們做了這么多事变姨,所以我們自己如果直接把組件的聲明包裝一下,返回一個高階組件厌丑,那么這個被包裝的組件就無法正常工作了
組件通信的區(qū)別
其實這部分兩個比較相似定欧。
在Vue 中有三種方式可以實現(xiàn)組件通信:
父組件通過 props 向子組件傳遞數(shù)據(jù)或者回調(diào),雖然可以傳遞回調(diào)怒竿,但是我們一般只傳數(shù)據(jù)砍鸠,而通過 事件的機制來處理子組件向父組件的通信
子組件通過 事件 向父組件發(fā)送消息
通過 V2.2.0 中新增的 provide/inject 來實現(xiàn)父組件向子組件注入數(shù)據(jù),可以跨越多個層級
另外有一些比如訪問 $parent/$children等比較dirty的方式這里就不講了耕驰。
在 React 中爷辱,也有對應的三種方式:
父組件通過 props 可以向子組件傳遞數(shù)據(jù)或者回調(diào)
可以通過 context 進行跨層級的通信,這其實和 provide/inject 起到的作用差不多。
可以看到饭弓,React 本身并不支持自定義事件巩检,Vue中子組件向父組件傳遞消息有兩種方式:事件和回調(diào)函數(shù),而且Vue更傾向于使用事件示启。
但是在 React 中我們都是使用回調(diào)函數(shù)的兢哭,這可能是他們二者最大的區(qū)別。
模板渲染方式的不同
在表層上夫嗓, 模板的語法不同
React 是通過JSX渲染模板
而Vue是通過一種拓展的HTML語法進行渲染
但其實這只是表面現(xiàn)象迟螺,畢竟React并不必須依賴JSX。
在深層上舍咖,模板的原理不同矩父,這才是他們的本質(zhì)區(qū)別:
React是在組件JS代碼中,通過原生JS實現(xiàn)模板中的常見語法排霉,比如插值窍株,條件,循環(huán)等攻柠,都是通過JS語法實現(xiàn)的
Vue是在和組件JS代碼分離的單獨的模板中球订,通過指令來實現(xiàn)的,比如條件語句就需要 v-if 來實現(xiàn)
對這一點瑰钮,我個人比較喜歡React的做法冒滩,因為他更加純粹更加原生,而Vue的做法顯得有些獨特浪谴,會把HTML弄得很亂开睡。
舉個例子,說明React的好處:
react中render函數(shù)是支持閉包特性的苟耻,所以我們import的組件在render中可以直接調(diào)用篇恒。
但是在Vue中,由于模板中使用的數(shù)據(jù)都必須掛在 this 上進行一次中轉凶杖,所以我們import 一個組件完了之后胁艰,還需要在 components 中再聲明下,這樣顯然是很奇怪但又不得不這樣的做法官卡。
Vuex 和 Redux 的區(qū)別
從表面上來說蝗茁,store 注入和使用方式有一些區(qū)別醋虏。
在 Vuex 中寻咒,$store 被直接注入到了組件實例中,因此可以比較靈活的使用:
使用 dispatch 和 commit 提交更新
通過 mapState 或者直接通過 this.$store 來讀取數(shù)據(jù)
在 Redux 中颈嚼,我們每一個組件都需要顯示的用 connect 把需要的 props 和 dispatch 連接起來毛秘。
另外 Vuex 更加靈活一些,組件中既可以 dispatch action 也可以 commit updates,而 Redux 中只能進行 dispatch叫挟,并不能直接調(diào)用 reducer 進行修改艰匙。
從實現(xiàn)原理上來說,最大的區(qū)別是兩點:
Redux 使用的是不可變數(shù)據(jù)抹恳,而Vuex的數(shù)據(jù)是可變的员凝。Redux每次都是用新的state替換舊的state,而Vuex是直接修改
Redux 在檢測數(shù)據(jù)變化的時候奋献,是通過 diff 的方式比較差異的健霹,而Vuex其實和Vue的原理一樣,是通過 getter/setter來比較的(如果看Vuex源碼會知道瓶蚂,其實他內(nèi)部直接創(chuàng)建一個Vue實例用來跟蹤數(shù)據(jù)變化)
而這兩點的區(qū)別糖埋,其實也是因為 React 和 Vue的設計理念上的區(qū)別。
React更偏向于構建穩(wěn)定大型的應用窃这,非常的科班化瞳别。
相比之下,Vue更偏向于簡單迅速的解決問題杭攻,更靈活祟敛,不那么嚴格遵循條條框框
因此也會給人一種大型項目用React,小型項目用 Vue 的感覺兆解。