這篇文章記錄我在使用Vue和React的時候,對他們的不同之處的一些思考,不僅侷限於他們本身,也會包括比如 Vuex/Redux
等經常搭配使用的工具。因為涉及到的內容很多,可能下面的每一個點都能寫成一篇文章,這次先簡單做一個概要,等我有空做一個詳細的專題出來。
監聽資料變化的實現原理不同
- Vue 通過
getter/setter
以及一些函式的劫持,能精確知道資料變化,不需要特別的優化就能達到很好的效能 - React 預設是通過比較引用的方式進行的,如果不優化(PureComponent/shouldComponentUpdate)可能導致大量不必要的VDOM的重新渲染
為什麼 React 不精確監聽資料變化呢?這是因為 Vue 和 React 設計理念上的區別,Vue 使用的是可變資料,而React更強調資料的不可變。所以應該說沒有好壞之分,Vue更加簡單,而React構建大型應用的時候更加魯棒。
因為一般都會用一個資料層的框架比如 Vuex
和 Redux
,所以這部分不作過多解釋,在最後的 vuex 和 redux的區別
中也會講到。
資料流的不同
大家都知道Vue中預設是支援雙向繫結的。在Vue1.0中我們可以實現兩種雙向繫結:
- 父子元件之間,
props
可以雙向繫結 - 元件與DOM之間可以通過
v-model
雙向繫結
在 Vue2.x 中去掉了第一種,也就是父子元件之間不能雙向繫結了(但是提供了一個語法糖自動幫你通過事件的方式修改),並且 Vue2.x 已經不鼓勵元件對自己的 props 進行任何修改了。
所以現在我們只有 元件 <--> DOM
之間的雙向繫結這一種。
然而 React 從誕生之初就不支援雙向繫結,React一直提倡的是單向資料流,他稱之為 onChange/setState()
模式。
不過由於我們一般都會用 Vuex
以及 Redux
等單向資料流的狀態管理框架,因此很多時候我們感受不到這一點的區別了。
HoC 和 mixins
在 Vue 中我們組合不同功能的方式是通過 mixin,而在React中我們通過 HoC (高階元件)。
React 最早也是使用 mixins
的,不過後來他們覺得這種方式對元件侵入太強會導致很多問題,就棄用了 mixinx 轉而使用 HoC
,關於mixin究竟哪裡不好,可以參見這篇文章 Mixins Considered Harmful。
而 Vue 一直是使用 mixin 來實現的。
為什麼 Vue 不採用 HoC 的方式來實現呢?
高階元件本質就是高階函式,React 的元件是一個純粹的函式,所以高階函式對React來說非常簡單。
但是Vue就不行了,Vue中元件是一個被包裝的函式,並不簡單的就是我們定義元件的時候傳入的物件或者函式。比如我們定義的模板怎麼被編譯的?比如宣告的props怎麼接收到的?這些都是vue建立元件例項的時候隱式乾的事。由於vue默默幫我們做了這麼多事,所以我們自己如果直接把元件的宣告包裝一下,返回一個高階元件,那麼這個被包裝的元件就無法正常工作了。
推薦一篇很棒的文章講的是vue中如何實現高階元件 探索Vue高階元件
元件通訊的區別
其實這部分兩個比較相似。
在Vue 中有三種方式可以實現元件通訊:
- 父元件通過
props
向子元件傳遞資料或者回撥,雖然可以傳遞迴調,但是我們一般只傳資料,而通過 事件的機制來處理子元件向父元件的通訊 - 子元件通過 事件 向父元件傳送訊息
- 通過
V2.2.0
中新增的provide/inject
來實現父元件向子元件注入資料,可以跨越多個層級。
另外有一些比如訪問 $parent/$children
等比較dirty的方式這裡就不講了。
在 React 中,也有對應的三種方式:
- 父元件通過
props
可以向子元件傳遞資料或者回撥 - 可以通過
context
進行跨層級的通訊,這其實和provide/inject
起到的作用差不多。
可以看到,React 本身並不支援自定義事件,Vue中子元件向父元件傳遞訊息有兩種方式:事件和回撥函式,而且Vue更傾向於使用事件。但是在 React 中我們都是使用回撥函式的,這可能是他們二者最大的區別。
模板渲染方式的不同
在表層上, 模板的語法不同
- React 是通過JSX渲染模板
- 而Vue是通過一種擴充的HTML語法進行渲染
但其實這只是表面現象,畢竟React並不必須依賴JSX。 在深層上,模板的原理不同,這才是他們的本質區別:
- React是在元件JS程式碼中,通過原生JS實現模板中的常見語法,比如插值,條件,迴圈等,都是通過JS語法實現的
- Vue是在和元件JS程式碼分離的單獨的模板中,通過指令來實現的,比如條件語句就需要
v-if
來實現
對這一點,我個人比較喜歡React的做法,因為他更加純粹更加原生,而Vue的做法顯得有些獨特,會把HTML弄得很亂。舉個例子,說明React的好處:
react中render函式是支援閉包特性的,所以我們import的元件在render中可以直接呼叫。但是在Vue中,由於模板中使用的資料都必須掛在 this
上進行一次中轉,所以我們import
一個元件完了之後,還需要在 components
中再宣告下,這樣顯然是很奇怪但又不得不這樣的做法。
Vuex 和 Redux 的區別
從表面上來說,store 注入和使用方式有一些區別。
在 Vuex 中,$store
被直接注入到了元件例項中,因此可以比較靈活的使用:
- 使用
dispatch
和commit
提交更新 - 通過
mapState
或者直接通過this.$store
來讀取資料
在 Redux 中,我們每一個元件都需要顯示的用 connect
把需要的 props
和 dispatch
連線起來。
另外 Vuex 更加靈活一些,元件中既可以 dispatch
action 也可以 commit
updates,而 Redux 中只能進行 dispatch
,並不能直接呼叫 reducer 進行修改。
從實現原理上來說,最大的區別是兩點:
- Redux 使用的是不可變資料,而Vuex的資料是可變的。Redux每次都是用新的state替換舊的state,而Vuex是直接修改
- Redux 在檢測資料變化的時候,是通過 diff 的方式比較差異的,而Vuex其實和Vue的原理一樣,是通過
getter/setter
來比較的(如果看Vuex原始碼會知道,其實他內部直接建立一個Vue例項用來跟蹤資料變化)
而這兩點的區別,其實也是因為 React 和 Vue的設計理念上的區別。React更偏向於構建穩定大型的應用,非常的科班化。相比之下,Vue更偏向於簡單迅速的解決問題,更靈活,不那麼嚴格遵循條條框框。因此也會給人一種大型專案用React,小型專案用 Vue 的感覺。的