- vue - 本質(zhì)是 MVVM 框架,由 MVC 發(fā)展而來(lái)
- React - 本質(zhì)是前端組件化框架,不是一個(gè)完整的MVC框架,可以認(rèn)為是MVC中的V(View)
MVVM
MVVM 的出現(xiàn)促進(jìn)了 GUI 前端開發(fā)與后端業(yè)務(wù)邏輯的分離,極大地提高了前端開發(fā)效率。MVVM 的核心是 ViewModel 層,它就像是一個(gè)中轉(zhuǎn)站(value converter),負(fù)責(zé)轉(zhuǎn)換 Model 中的數(shù)據(jù)對(duì)象來(lái)讓數(shù)據(jù)變得更容易管理和使用,該層向上與視圖層進(jìn)行雙向數(shù)據(jù)綁定,向下與 Model 層通過(guò)接口請(qǐng)求進(jìn)行數(shù)據(jù)交互,起呈上啟下作用。如下圖所示

MVVM的設(shè)計(jì)思想:關(guān)注Model的變化,讓MVVM框架去自動(dòng)更新DOM的狀態(tài),從而把發(fā)者從操作DOM的繁瑣步驟中解脫出來(lái)!
Bug很難被調(diào)試。因?yàn)槭褂秒p向綁定的模式,當(dāng)你看到界面異常了,有可能是你View的代碼有Bug,也可能是Model的代碼有問(wèn)題。數(shù)據(jù)綁定使得一個(gè)位置的Bug被快速傳遞到別的位置,要定位原始出問(wèn)題的地方就變得不那么容易了。另外,數(shù)據(jù)綁定的聲明是指令式地寫在View的模版當(dāng)中的,這些內(nèi)容是沒(méi)辦法去打斷點(diǎn)debug的。
一個(gè)大的模塊中model也會(huì)很大,雖然使用方便了也很容易保證了數(shù)據(jù)的一致性,當(dāng)時(shí)長(zhǎng)期持有,不釋放內(nèi)存就造成了花費(fèi)更多的內(nèi)存。
對(duì)于大型的圖形應(yīng)用程序,視圖狀態(tài)較多,ViewModel的構(gòu)建和維護(hù)的成本都會(huì)比較高。

生命周期
Vue生命周期

React為每個(gè)組件提供了生命周期鉤子函數(shù)去響應(yīng)不同的時(shí)刻,組件的生命周期分為三個(gè)部分:(1)實(shí)例化;(2)存在期;(3)銷毀&清理期。具體周期如下圖所示:
React v16.3以前版本

React v16.3以后版本

數(shù)據(jù)流管理
Vue組件數(shù)據(jù)流的問(wèn)題
而vue的思想是響應(yīng)式的,也就是基于是數(shù)據(jù)可變的,通過(guò)對(duì)每一個(gè)屬性建立Watcher來(lái)監(jiān)聽,當(dāng)屬性變化的時(shí)候,響應(yīng)式的更新對(duì)應(yīng)的虛擬dom。

React數(shù)據(jù)是單向不可變的
react是自上而下的單向組件數(shù)據(jù)流,容器組件&展示組件(也叫傻瓜組s件&聰明組件)是最常用的react組件設(shè)計(jì)方案,容器組件負(fù)責(zé)處理復(fù)雜的業(yè)務(wù)邏輯以及數(shù)據(jù),展示組件負(fù)責(zé)處理UI層,通常我們會(huì)將展示組件抽出來(lái)進(jìn)行復(fù)用或者組件庫(kù)的封裝,容器組件自身通過(guò)state來(lái)管理狀態(tài),setState更新狀態(tài),從而更新UI,通過(guò)props將自身的state傳遞給展示組件實(shí)現(xiàn)通信。
這是當(dāng)業(yè)務(wù)需求不復(fù)雜,頁(yè)面較簡(jiǎn)單時(shí)我們常用的數(shù)據(jù)流處理方式,僅用react自身提供的props和state來(lái)管理足矣,但是如果稍微增加一點(diǎn)復(fù)雜度呢,比如當(dāng)我們項(xiàng)目中遇到這些問(wèn)題:

1,如何實(shí)現(xiàn)跨組件通信、狀態(tài)同步以及狀態(tài)共享?
react V16.3以前,通過(guò)狀態(tài)提升至最近的共同父組件來(lái)實(shí)現(xiàn)。(雖然有官方提供的context API,但是舊版本存在一個(gè)問(wèn)題:看似跨組件,實(shí)則還是逐級(jí)傳遞,如果中間組件使用了ShouldComponentUpdate檢測(cè)到當(dāng)前state和props沒(méi)有變化,return false,那么context就會(huì)無(wú)法透?jìng)?,因此context沒(méi)有被官方推薦使

react V16.3版本以后,新版本context解決了之前的問(wèn)題,可以輕松實(shí)現(xiàn),但依然存在一個(gè)問(wèn)題,context也是將底部子組件的狀態(tài)控制交給到了頂級(jí)組件,但是頂級(jí)組件狀態(tài)更新的時(shí)候一定會(huì)觸發(fā)所有子組件的re-render,那么也會(huì)帶來(lái)?yè)p耗。(雖然我們可以通過(guò)一些手段來(lái)減少重繪,比如在中間組件的SCU里進(jìn)行一些判斷,但是當(dāng)項(xiàng)目較大時(shí),我們需要花太多的精力去做這件事)

2,如何避免組件臃腫?
當(dāng)某個(gè)組件的業(yè)務(wù)邏輯非常復(fù)雜時(shí),我們會(huì)發(fā)現(xiàn)代碼越寫越多,因?yàn)槲覀冎荒茉诮M件內(nèi)部去控制數(shù)據(jù)流,沒(méi)辦法抽離,Model和View都放在了View層,整個(gè)組件顯得臃腫不堪,業(yè)務(wù)邏輯統(tǒng)統(tǒng)堆在一塊,難以維護(hù)。
3,如何讓狀態(tài)變得可預(yù)知,甚至可回溯?
當(dāng)數(shù)據(jù)流混亂時(shí),我們一個(gè)執(zhí)行動(dòng)作可能會(huì)觸發(fā)一系列的setState,我們?nèi)绾文軌蜃屨麄€(gè)數(shù)據(jù)流變得可“監(jiān)控”,甚至可以更細(xì)致地去控制每一步數(shù)據(jù)或狀態(tài)的變更?
4,如何處理異步數(shù)據(jù)流?
react自身并未提供多種處理異步數(shù)據(jù)流管理的方案,僅用一個(gè)setState已經(jīng)很難滿足一些復(fù)雜的異步流場(chǎng)景;
組件通信

其實(shí)這部分兩個(gè)比較相似。在Vue 中有三種方式可以實(shí)現(xiàn)組件通信:
- 父組件通過(guò)props向子組件傳遞數(shù)據(jù)或者回調(diào),雖然可以傳遞回調(diào),但是我們一般只傳數(shù)據(jù),只需通過(guò)事件的機(jī)制來(lái)處理
- 子組件向父組件的通信子組件通過(guò)事件 向父組件發(fā)送消息
- 通過(guò) V2.2.0 中新增的 provide/inject 來(lái)實(shí)現(xiàn)父組件向子組件注入數(shù)據(jù),可以跨越多個(gè)層級(jí)。
- 訪問(wèn)
children等不合編碼規(guī)范的方式。
在React中,組件是如何通信的呢?
- 父組件通過(guò) props 可以向子組件傳遞數(shù)據(jù)或者回調(diào)
- 通過(guò) context 進(jìn)行跨層級(jí)的通信,這其實(shí)和 provide/inject 起到的作用差不多。
React不支持自定義事件,Vue中子組件向父組件傳遞消息有兩種方式:事件和回調(diào)函數(shù),而且Vue更傾向于使用事件。但是在 React 中我們都是使用回調(diào)函數(shù)的,這可能是他們二者最大的區(qū)別。
模版上不同
- vue - 使用模板(最初由 angular 提出)
- React - 使用 JSX
條件判斷

循環(huán)遍歷生成

JSX

總結(jié)
- 模板語(yǔ)法上,我更加傾向于 JSX
- 模板分離上,我更加傾向于 vue
補(bǔ)充說(shuō)明
- JSX 語(yǔ)法(標(biāo)簽、JS 表達(dá)式、判斷、循環(huán)、事件綁定)
- JSX 是語(yǔ)法糖,需被解析成 JS 才能運(yùn)行
- JSX 是 React 引入的,但不是 React 獨(dú)有的, 是獨(dú)立的標(biāo)準(zhǔn),可被其他項(xiàng)目使用
VDOM
React
React在開發(fā)初期就引入虛擬DOM概念,后來(lái)發(fā)現(xiàn)很好用,但是這是一個(gè)無(wú)心插柳的結(jié)果, 但React的核心思想:組件化,一個(gè)Component拯救世界,忘掉煩惱,從此不再操心界面。
為什Virtual Dom快? Javascript很快, Dom很慢 ~
vue:Vue在2.0版本引入了vdom。其vdom是基于snabbdom 庫(kù)所做的修改。snabbdom是一個(gè)開源的vdom庫(kù)。snabbdom的主要作用就是將傳入的JS模擬的DOM結(jié)構(gòu)轉(zhuǎn)換成虛擬的DOM節(jié)點(diǎn)。先通過(guò)其中的 h函數(shù) 將JS模擬的DOM結(jié)構(gòu)轉(zhuǎn)換成虛擬DOM之后,再通過(guò)其中的 patch函數(shù) 將虛擬DOM轉(zhuǎn)換成真實(shí)的DOM渲染到頁(yè)面中。為了保證頁(yè)面的最小化渲染,snabbdom引入了Diff算法 ,通過(guò)Diff算法找出前后兩個(gè)虛擬DOM之間的差異,只更新改變了的DOM節(jié)點(diǎn),而不重新渲染為改變的DOM節(jié)點(diǎn)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<p id="container"></p>
<button id="btn-change">change</button>
<!-- 引入snabbdom庫(kù),先不必糾結(jié)為什么這樣引入,以及每個(gè)文件的作用。 -->
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-class.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-props.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-style.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-eventlisteners.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.1/h.js"></script>
<script>
//定義patch函數(shù)
var patch = snabbdom.init([
snabbdom_class,
snabbdom_props,
snabbdom_style,
snabbdom_eventlisteners
])
//定義h函數(shù)
var h = snabbdom.h;
//生成一個(gè)vnode
var vnode = h('ul#list',{},[
h('li.item',{},['Item 1']),
h('li.item',{},['Item 2']),
])
console.log(vnode);
//獲取container
var container = document.getElementById('container');
patch(container,vnode);//初次渲染
var btn = document.getElementById('btn-change');
btn.onclick = function() {
var newVnode = h('ul#list',{},[
h('li.item',{},['Item 1']),
h('li.item',{},['Item B']),
h('li.item',{},['Item 3']),
])
patch(vnode,newVnode);//再次渲染
vnode = newVnode;//將修改后的newVnode賦值給vnode
}
</script>
</body>
</html>
vue中的模板解析和渲染的核心就是:通過(guò)類似snabbdom的h()和patch()的函數(shù),先將模板解析成vnode,如果是初次渲染,則通過(guò)patch(container,vnode)將vnode渲染至頁(yè)面,如果是二次渲染,則通過(guò)patch(vnode,newVnode),先通過(guò)Diff算法比較原vnode和newVnode的差異,以最小的代價(jià)重新渲染頁(yè)面。
組件化的區(qū)別
- React 本身就是組件化,沒(méi)有組件化就不是 React
- vue 也支持組件化,不過(guò)是在 MVVM 上的擴(kuò)展
- 對(duì)于組件化,我更加傾向于 React ,做的徹底而清晰
共同點(diǎn)
- 都支持組件化
- 都是數(shù)據(jù)驅(qū)動(dòng)試圖
Chrome 開發(fā)工具
React和Vue都有很好的Chrome擴(kuò)展工具去幫助你找出bug。它們會(huì)檢查你的應(yīng)用,讓你看到Vue或者React中的變化。你也可以看到應(yīng)用中的狀態(tài),并實(shí)時(shí)看到更新。
- React的開發(fā)工具: http://www.itdecent.cn/p/06df38a956dc
- Vue的開發(fā)工具: http://www.itdecent.cn/p/dab699ca2fd4
DEMO展示
參考文章: