不吹不黑比對下React與Vue的差別與優劣

react與vue的比較一直是一個比較引戰與容易引發爭議的話題,或許每一個前端都或多或少的參與到過這場辯論中,可是在這場巨大的辯論中產出的有價值的內容卻一直比較稀缺。在這裏我無心再次引發爭吵,只是結合我本身的經驗但願儘量客觀的闡述一些我認爲的兩個框架上一些差異與優劣。事實上若是沒有真的在生產環境中較多的使用過兩個框架而只是根據文檔與一些demo來作對比幾乎是沒有什麼實際的意義的。我在前一年的工做中幾乎只使用vue,由於當時上一家公司部門的技術棧只是vue,雖然我也學習了react而且根據文檔作了一些demo,但當我當時真正去想知道react與vue之間的具體差異是什麼從而去找一些react的文章來讀時會發現,由於沒有實踐與系統的研究過react很難真正的弄清楚這二者的真正差別。而現在當我大概真正寫了3個月左右的react後,最大的發現實際上是不少差別你寫着寫着它本身就會慢慢的浮到水面上,因此建議部門技術棧寬鬆的同窗仍是多去嘗試,弄清楚問題的最好的方式應該是本身試着解答它。前端

如下只表明我的的意見,並不保證觀點所有正確vue

diff、patch與update

react: 在react中若是某個組件的狀態發生改變,react會把此組件以及此組件的全部後代組件從新渲染,不太重新渲染並不表明會所有丟棄上一次的渲染結果,react中間仍是會經過diff去比較兩次的虛擬dom最後patch到真實的dom上。雖然如此,若是組件樹過大,diff其實仍是會有一部分的開銷,由於diff的過程依然是比較以此組件爲根的整顆組件樹。react提供給咱們的解決方案是shouldComponentUpdate,以此函數的返回結果來判斷是否須要執行後面的diff、patch與update。再實際的開發過程當中咱們經常會用pureComponent來幫助咱們作這一層邏輯判斷,但須要注意的是pureComponentshouldComponentUpdate也只是淺比較,假設比較的類型是object,若是object僅屬性發生變化,可是其引用沒發生變化那麼shouldComponentUpdate會認爲二者之間沒有任何變化。react

vue: vue的響應式使用的是Object.definePropertyapi,而且因爲在getter中實現了依賴收集,因此不會像react同樣去比較整顆組件樹,而是更加細粒度的去更新狀態有變化的組件,同時defineProperty也不存在像shouldComponentUpdate中比較引用的問題。git

對比: vue的更新要比react粒度要更細也更加不用去人爲的關心,雖然react能夠經過shouldComponentUpdate實現一樣的效果,然而若是state的層級結構比較深那麼相應的手動去優化這部分代碼也會更加費力,因此在react中咱們須要儘可能保證總體結構的扁平,去讓pureComponent幫助咱們自動的對此做出優化。github

狀態數據的更改方式

react: 因爲react與redux推崇的都是函數式編程,因此相似的狀態更改都相似以下代碼編程

state = {
    obj: {a: 1, b: 2},
    arr: [1, 2, 3],
}

// 修改obj.b
modifyObj = () => {
    this.setState({
        obj: {
            ...this.state.obj,
            b: 3,
        }
    })
}

// 修改arr
modifyArr = () => {
    this.setState({
        arr: [...this.state.arr, 4],
    })
}
複製代碼

實際上咱們就算直接修改對象或是數組也是能夠的,好比直接修改obj.b = 3,而後setState({ obj }),一些狀況下這並不會引發什麼錯誤,可是第一因爲react與redux自己就是推崇函數式編程的,因此官方是不推薦直接修改對象或數組。第二還記的咱們上面說的pureComponent嗎,因爲shouldComponentUpdate是淺比較,若是直接修改對象或者數組的話會致使組件並不會發生更新。redux

vue: vue在修改狀態數據來講相對是比較簡單的,對於對象咱們能夠直接this.obj.b = 3就能夠了,此時會觸發初次渲染時設置的setter,而後會調用notify方法去通知全部watcher執行update。可是對於數組的修改來講vue就並無這麼簡潔了,雖然咱們依然能夠經過push,unshift等方法去修改數組,可是相似arr[index] = someVal這種方式就行不通了,此時或者使用splice方法,或者經過相似react的方式map一個新的數組從新賦值。最近vue3也逐漸浮出了水面,再最近這幾回的vueConf中宣佈了vue3採用的是proxy方案,因此在vue3中數組的改變就可使用arr[index]的方式了。api

對比: 在data爲對象的狀況下,vue的代碼方式要更加簡單方便,而數組的狀況下對於vue與react其實並無什麼太大的差異,至關多的時候咱們依然要使用map,filter等函數。可是注意vue的簡單方便並不表明自己更好,react與redux之因此推崇永遠用新的值代替舊值爲的是更加容易debug與一些時間旅行等功能,但對於vue來講這並不衝突,若是你喜歡你一樣能夠用這種方式去書寫你的vue代碼。另一提,雖然看起來Object.defineProperty這個api幫助了vue不少,但也不是全無反作用的,當狀態數據龐大時,因爲此api須要遞歸的去不斷的對狀態數據執行監聽,因此vue的初始消耗有可能更多,對應的也就是白屏時間相對react來講更長,此問題也會在vue3中解決,由於基於proxy的監聽是相似lazy這種形式的。數組

關於邏輯複用

react: 關於邏輯複用是一塊頗有意思的內容,真的要感慨一下react的社區與社區貢獻的高質量方案,從mixin到高階組件再到renderProps,咱們這裏主要拿renderProps來舉例,高階組件咱們留到後面說。所謂的邏輯復就是把通用的一些邏輯複用到須要這些邏輯的組件上,咱們來看下react官方文檔爲咱們提供的案例。bash

這是一個實時顯示鼠標位置的組件,對於這個組件來講主要邏輯在於鼠標事件的處理,可是這一部分又偏偏是比較難複用的一個地方,假設咱們但願在另外一個組件中渲染一張貓的圖片,同時它的位置由鼠標位置決定,那麼這部分鼠標事件與狀態的代碼咱們基本上又要再寫另外一遍,來看下renderProps是怎麼解決問題的。

第一次看這樣的代碼真的是要稍微感嘆一下這他媽怎麼想到的,抽象出Mouse組件負責行爲,而後將state做爲參數傳入外部返回組件的函數中,真的是感受至關牛逼。順帶一提,並不必定要用render這種props,好比這個例子裏咱們徹底能夠寫成如代碼的形式

<Mouse>
    {
        mouse => <Cat mouse={mouse} />
    }
</Mouse>

// Mouse組件
<div onMouseMove={this.handleMouse}>{this.props.children(this.state)}</div>
複製代碼

相對應的咱們能夠作出不少這樣的封裝,好比模態框的開關,好比Input,Select等控件關於onChange與setState的封裝,簡單舉一個例子

<Container>
{
    (value, changeValue) => <Input value={value} onChange={changeValue} />
}
</Container>
複製代碼

想象一個常見的場景,4個Input外加一個Button搜索按鈕,而後將搜索出的數據展現到表格上,使用這種封裝能夠省下至關多的樣板代碼。

vue: 咱們直接看看vue怎麼實現上面的鼠標複用邏輯把。

// 指令
Vue.directive('mouse', {
  binding: function (el, binding) {
    function mouseMove(e) {
        binding.value.x = e.clientX;
        binding.value.y = e.clientY;
    }
    el.__mouseMove = mouseMove;
    el.addEventListener('mousemove', mouseMove);
  },
  unbinding: function (el) {
      el.removeEventListener('mousemove', el.__mouseMove);
  }
})

// 組件中
<template>
    <div v-model="data">
        {{ data.x }}, {{ data.y }}
    </div>
</template>
複製代碼

直接註冊一個v-mouse指令,咱們就能夠在任意組件去複用這段邏輯了,其實單論這兩段代碼我我的認爲vue的實現是更好的,v-mouse這種聲明式的指令很是的清晰與優雅,可是可是可是咱們必需要清楚這只是很簡單的一小段邏輯,若是邏輯更加複雜,毫無疑問的是react靈活性與維護性上都要比指令的方式好上很是多。

對比: react的renderProps雖然稍爲繁瑣一點可是在靈活性與可維護性上來講是要絕對優於vue的指令的。可是在一些簡單的場景下vue的指令也確實會至關的方便,好比最經常使用的內置v-model,依然想一下咱們以前描述的場景,多個Input加一個按鈕,vue對應的只是4個v-model="value"

數據的流向

其實這一部分並不算二者有差別的部分,可是不少人一看到v-model就下意識的反應雙向數據綁定。不少比較vue與react的回答直到今天還會說因爲vue是雙向數據綁定,致使數據容易變得混亂在大型項目中不易維護,這實在是有些搞笑的。其實再組件間vue與react的數據流向都是單向的由父向子,而且子組件不容許改變props,二者並無什麼區別,而相似input中的v-model不過是邏輯複用的一種方式或者說是一種聲明式的語法糖,一樣的爲組件使用v-model依然是一種語法糖,可是數據的流向仍然是清晰的單向流動。

高階組件

react: 高階組件是另外一種複用邏輯的形式,對比renderProps,高階組件其實更多的是選擇傳入什麼,而renderProps則是暴漏什麼。所謂的高階組件其實跟高階函數是一個意思,只不過函數接收的是一個組件而後再返回一個組件, 舉一個經常使用的例子,假設咱們有一個接口是獲取公司的組織樹,這個組織樹在不少場景下都要使用,咱們就能夠抽出一個公用的高階組件

function HOC(wrapperComponent) {
    return class getOrgTree extends React.Component {
        state = { orgTree: [] }
        
        componentDidMount() {
            fetch('xxxxxxx').then(orgTree => this.setState({ orgTree }))
        }
        
        render() {
            return <wrapperComponent orgTree={this.state.orgTree} {...this.props} />
        }
    }
}
複製代碼

經過這個函數咱們能夠把任意咱們本身的組件傳入函數使其擁有orgTree的props,除此以外咱們還能夠經過高階組件去減小或增長各類props等拓展性的操做

vue: vue的相似操做幾乎只能經過mixin來實現(容易污染,也不容易debug),更是很難去拓展使用mixin的組件,這二者的區別像是react的組件像是穿上了一層裝甲變了身,vue的組件只是把東西拿過來放在口袋裏本質上仍是本身。

const myMixin = {
  created: function () {
    fetch('xxxxx').then(orgTree => this.orgTree = orgTree)
  },
}
複製代碼

對比: 在高階函數這個階段react經過面向對象的方式依然達到了一個高擴展性與靈活性,vue在高階函數中幾乎沒什麼發揮餘地,由於vue其實是面向配置(options)的,雖然咱們能夠利用render函數楞寫一個貌似高階組件的東西,可是第一render書寫的代碼可讀性仍是不好的(雖然貌似也可使用babel寫jsx,但那樣爲何不直接用react),第二這也幾乎背離了vue的開發模式,因此其實從一些模式上的應用與邏輯上的複用角度來說react是領先的。不過好消息是vue3的組件也是class了,這或許能幫助vue在這個短板上提高。

TypeScript支持

對比: vue2雖然支持,可是使用上並不良好,落後react不少個等級。依然是vue3解決的問題。

社區與周邊生態

對比: 事實上我認爲真正react與vue之間的差距很大一部分是在社區與一些生態上,react的社區貢獻真的是至關的活躍,各類各樣的方案,各類成熟的組件(不僅是UI庫),相對而言vue則顯得平靜不少,有不少組件的質量也還不夠高,這個就並非vue3能解決的問題了,惟一能依靠的只有時間。

總結

結論與不少對比同樣,vue適合小而精的項目,react則更適用於偏大的項目,可是立住這個結論的支點是不同的,vue的組件因爲一些複雜邏輯的複用方式和組件可應用模式的不足,以致於在大型項目中複用性與設計性是不如react的,可是在小而精的項目裏,vue更友好的書寫方式,更簡化的代碼與更聲明式的指令都是很棒的優點與特色,而相反的react在中大型項目中能更好的完成vue的不足項,可是也更須要團隊技術總體比較給力,領頭大佬的設計與把關能力要更優秀,否則糟糕的設計或許不如沒有設計。有一些比較總會認爲vue因爲api較多書寫更靈活致使最後的代碼難以維護,事實上react或許纔是更靈活的一個,由於react幾乎沒有api致使不管怎樣的寫代碼都是可行的,團隊中有10我的可能就有10種方式去理解react,而且不管是狀態管理仍是異步中間件再加上路由等等,react的社區都提供了更多的選項,怎麼選型,採用什麼方案也是稍使人頭疼的事情之一。

最後

原文地址:github.com/wangweida/b…

都讀到這了,以爲還行給個star總不過度~~~

相關文章
相關標籤/搜索