淺聊 React & Vue

比較.jpg

? 沒有對比就沒有傷害,今天突發(fā)奇想想對Vue和React的使用體驗(yàn)進(jìn)行一下總結(jié)餐蔬,隨便比較下兩者。網(wǎng)絡(luò)上對比兩者比較的各種的文章一大把佑附,眾說紛紜樊诺。接觸和使用Vue和React已經(jīng)很長時(shí)間了,給自己最直接的感覺是:兩者并沒有太明顯的差別音同,畢竟完成的是同一件事情(業(yè)務(wù)頁面開發(fā))词爬,但如果是先用Vue,再用React的权均,會發(fā)現(xiàn)之前感覺Vue那種模板化和數(shù)據(jù)視圖分離的編碼方式很先進(jìn)很牛逼顿膨,而寫熟了React的JSX語法,和組件化的思想叽赊,一下子又覺得React的哲學(xué)思想又先進(jìn)一點(diǎn)恋沃。所以總結(jié)下來,好比飯局上喝紅酒還是白酒必指,不同時(shí)期給人感覺不一樣囊咏。下文,不帶偏見的聊聊兩者塔橡。

發(fā)展歷史

百科一把:

React 起源于 Facebook 的內(nèi)部項(xiàng)目梅割,因?yàn)樵摴緦κ袌錾纤?JavaScript MVC 框架,都不滿意葛家,就決定自己寫一套户辞,用來架設(shè)Instagram 的網(wǎng)站。做出來以后癞谒,發(fā)現(xiàn)這套東西很好用底燎,就在2013年5月開源了。

Vue 是一套用于構(gòu)建用戶界面的漸進(jìn)式JavaScript框架扯俱。與其它大型框架不同的是书蚪,Vue 被設(shè)計(jì)為可以自底向上逐層應(yīng)用。Vue 的核心庫只關(guān)注視圖層迅栅,方便與第三方庫或既有項(xiàng)目整合殊校。

? 從介紹來看,兩個(gè)框架都是MVC模式的延續(xù)读存,或者叫改進(jìn)为流。React更側(cè)著于V呕屎,正如介紹的“React主要用于構(gòu)建UI”,React更關(guān)心的是UI的組件化敬察,而Vue則在MVC的基礎(chǔ)上提出了MVVM的思想秀睛。

國內(nèi)使用情況:

? BAT主流使用React多一點(diǎn),普通互聯(lián)網(wǎng)和傳統(tǒng)軟件公司還是Vue多一點(diǎn)(沒有統(tǒng)計(jì)數(shù)據(jù)支撐莲祸,屬于筆者意淫)蹂安。

原理分析

Vue代碼:

main.js

import Vue from 'vue'
import App from './App'

new Vue({
  el: '#app',
  components: { App },
  render: h => h(App)
})

App.vue

<template>
  <div id="app">
    <ToList />
  </div>
</template>

<script>
import ToList from './components/ToList'
export default {
  components: { ToList },
  name: 'App'
}
</script>

ToList.vue

<template>
  <div>
    <div>
      <input v-model="inputValue" />
      <button @click="handleSubmit">提交</button>
    </div>
    <ul>
      <li v-for="(item,index) of list"
          :key="index">
        {{item}}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: 'ToList',
  data () {
    return {
      inputValue: '', list: []
    }
  },
  methods: {
    handleSubmit: function () {
      this.list.push(this.inputValue)
      this.inputValue = ''
    }
  }
}
</script>

? 雖然編寫代碼的時(shí)候分了三個(gè)文件,但是通過webpack的vue-loader等插件锐帜,最終build完田盈,其實(shí)只生成了一個(gè)有效的JS文件:app.XXXX.js〗裳郑可以這么理解允瞧,瀏覽器其實(shí)識別不了vue這樣的文件的,瀏覽器能解析的就是js\html\css蛮拔。vue內(nèi)部的script部分我們可以理解述暂,那么我們來分析分析template最終會變成什么樣的格式。取消webpack混淆壓縮插件:UglifyJsPlugin建炫,最終摳出來的轉(zhuǎn)換后腳本如下:

var ToList = {
    name: 'ToList',
    data: function data () {
        return {
            inputValue: '',
            list: []
        }
    },

    methods: {
        handleSubmit: function handleSubmit () {
            this.list.push(this.inputValue)
            this.inputValue = ''
        }
    }
}

var ToList_render = function () {
    var _vm = this
    var _h = _vm.$createElement
    var _c = _vm._self._c || _h
    //templete最終變成了js版本的vnode結(jié)構(gòu)
    return _c('div', [
        _c('div', [
            _c('input', {
                directives: [
                    {
                        name: 'model',
                        rawName: 'v-model',
                        value: _vm.inputValue,
                        expression: 'inputValue'
                    }
                ],
                domProps: { value: _vm.inputValue },
                on: {
                    input: function ($event) {
                        if ($event.target.composing) {
                            return
                        }
                        _vm.inputValue = $event.target.value
                    }
                }
            }),
            _vm._v(' '),
            _c('button', { on: { click: _vm.handleSubmit } }, [_vm._v('提交')])
        ]),
        _vm._v(' '),
        _c(
            'ul',
            _vm._l(_vm.list, function (item, index) {
                return _c('li', { key: index }, [
                    _vm._v('\n      ' + _vm._s(item) + '\n    ')
                ])
            }),
            0
        )
    ])
}

? 可以發(fā)現(xiàn)畦韭,template其實(shí)最終轉(zhuǎn)換為用JS描述的Dom結(jié)構(gòu)(ToList_render),而這個(gè)結(jié)構(gòu)其實(shí)就是虛擬節(jié)點(diǎn)(虛擬Dom)踱卵。并且v-model這類指令的標(biāo)簽廊驼,Vue自動給我們注冊了input事件,值發(fā)生變化后自動賦值給綁定的數(shù)據(jù)惋砂。頁面加載后妒挎,通過ToList_render函數(shù),虛擬DOM就把JS-DOM渲染到了真實(shí)的DOM西饵。

? 那么既然是MVVM酝掩,數(shù)據(jù)發(fā)生變化,怎么更新到標(biāo)簽控件呢眷柔。上面的代碼當(dāng)然不能解釋期虾,閱讀Vue源碼其實(shí)可以大致發(fā)現(xiàn),Vue采用了一個(gè)JS方法:Object.defineProperty()驯嘱,通過vm的data對象镶苞,代理了真實(shí)data,從而感知data的get和set鞠评,然后通過上面的虛擬dom茂蚓,改變具體的標(biāo)簽值,再通過虛擬DOM庫Diff到真實(shí)Dom。

MVVM.png

React代碼

    /*
    1)拆分組件: 拆分界面,抽取組件
    2)實(shí)現(xiàn)靜態(tài)組件: 使用組件實(shí)現(xiàn)靜態(tài)頁面效果
    3)實(shí)現(xiàn)動態(tài)組件
        ① 動態(tài)顯示初始化數(shù)據(jù)
        ② 交互功能(從綁定事件監(jiān)聽開始)
     */
    // 應(yīng)用組件
    class App extends React.Component {
      constructor (props) {
        super(props)
        // 初始化狀態(tài)
        this.state = {
          todos: ['吃飯', '睡覺', '打豆豆']
        }
        this.add = this.add.bind(this)
      }
      add (todo) {
        const {todos} = this.state
        todos.unshift(todo)
        //更新狀態(tài)
        this.setState({todos})
      }
      render () {
        const {todos} = this.state
        return (
          <div style={{color:'red'}}>
            <TodoAdd add={this.add} count={todos.length} />
            <TodoList todos={todos} />
          </div>
        )
      }
    }

    // 添加todo組件
    class TodoAdd extends React.Component {
      constructor (props) {
        super(props)
        this.addTodo = this.addTodo.bind(this)
      }
      addTodo () {
        // 讀取輸入數(shù)據(jù)
        const text = this.input.value.trim()
        // 查檢
        if(!text) {
          return
        }
        // 保存到todos
        this.props.add(text)
        // 清除輸入
        this.input.value = ''
      }
      render () {
        return (
          <div>
            <h2>Simple TODO List</h2>
            <input type="text" ref={input => this.input=input}/>
            <button onClick={this.addTodo}>Add #{this.props.count}</button>
          </div>
        )
      }
    }
    TodoAdd.propTypes = {
      add: PropTypes.func.isRequired,
      count: PropTypes.number.isRequired
    }

    // todo列表組件
    class TodoList extends React.Component {
      render () {
        const {todos} = this.props
        return (
          <ul>
            {
              todos.map((todo, index) => <li key={index}>{todo}</li>)
            }
          </ul>
        )
      }
    }
    TodoList.propTypes = {
      todos: PropTypes.array.isRequired
    }

    // 渲染應(yīng)用組件標(biāo)簽
    ReactDOM.render(<App />, document.getElementById('root'))

? 首先React入門解釋就說明了一個(gè)問題聋涨,render函數(shù)里面返回的是一個(gè)JSX語法的代碼晾浴,而JSX的作用就是用來描述html的DOM結(jié)構(gòu)的,也就是說React在build的完后牍白,其實(shí)JSX已經(jīng)轉(zhuǎn)換為JS結(jié)構(gòu)的DOM描述脊凰。如果沒法直觀理解,可以參考下React官方介紹 jsx:

JSX.png

? 那么頁面加載完成后茂腥,ReactJS做的事情狸涌,似乎和Vue是一樣的,把JS-Dom 掛載到真實(shí)頁面础芍,也就是Diff掛載杈抢。那么問題來了,React既然不是MVVM這類雙向的數(shù)據(jù)綁定仑性,自稱是單向的,它單向又如何實(shí)現(xiàn)呢右蹦。第一次接觸React诊杆,其實(shí)就發(fā)現(xiàn)了一個(gè)特點(diǎn)setState函數(shù)。個(gè)人感覺何陆,這是一個(gè)設(shè)計(jì)局限問題晨汹,React沒法像Vue那樣自然的修改data的值,它為了實(shí)現(xiàn)數(shù)據(jù)變化改變視圖贷盲,委婉的約定了改變數(shù)據(jù)用setState函數(shù)淘这。其實(shí)setState里面就間接的完成了Vue里面的數(shù)據(jù)發(fā)生變化的感知過程(這當(dāng)然是廢話,用戶直接調(diào)用函數(shù)去修改數(shù)據(jù)了巩剖,當(dāng)然直接感知了)铝穷。setState里面重新通過render函數(shù)渲染了虛擬Dom,然后再diff更新到真實(shí)dom。React既然都委婉的采用了setState佳魔,那自然可以對setState下些功夫了曙聂,異步更新(隊(duì)列式更新),合并更新鞠鲜,借此來宣稱一些性能上的優(yōu)化宁脊,當(dāng)然也由此產(chǎn)生了各種不便和問題。

React-V.png

對比點(diǎn)

  • 數(shù)據(jù)驅(qū)動

都采用數(shù)據(jù)驅(qū)動視圖的思想贤姆,上來就是data數(shù)據(jù)和state數(shù)據(jù)榆苞,讓開發(fā)人員一目了然的明白,我們干的事情就是數(shù)據(jù)來驅(qū)動視圖的變化霞捡,業(yè)務(wù)開發(fā)的核心是數(shù)據(jù)坐漏。

  • 模板&虛擬Dom

雖然虛擬Dom化,Vue從2.0版本才引入了虛擬Dom,但到目前為止兩者這方面的思想是一致的仙畦。通過Template也好输涕,或者JSX也好,做的同一件事情慨畸,把html標(biāo)簽搞成js描述的Dom結(jié)構(gòu)莱坎。其實(shí)回頭想想,也只能用javascript語言來描述這個(gè)dom寸士。為啥檐什?這樣可以寫很多邏輯在里面,而帶邏輯的描述語言弱卡,在瀏覽器端時(shí)候也只有js合適乃正。另外要配合差異化更新(diff),似乎也只有采用內(nèi)存比較才高效。當(dāng)然Diff算法婶博,兩者還是有差異的瓮具,但思想還是一樣的。

  • MVVM&單向

我目前為止了解到的凡人,React為啥只實(shí)現(xiàn) 了單向名党,可以理解為簡單化,并非100%的數(shù)據(jù)都需要雙向挠轴,而且單向的過程簡單明了传睹,況且開發(fā)人員可以自行實(shí)現(xiàn)雙向綁定。而Vue的雙向岸晦,就是MVVM的核心體現(xiàn)了欧啤,這是它的優(yōu)勢,當(dāng)然的確也帶來了很多便利启上,尤其是表單開發(fā)過程邢隧。

  • 組件化

說完MVVM和單向,組件化過程兩者的確都實(shí)現(xiàn)了碧绞,但React的組件化才把組件的概念體現(xiàn)的淋漓盡致府框。甚至函數(shù)即組件的概念,能夠直白的讓開發(fā)員理解啥是組件讥邻。而Vue的組件明顯是在MVVM的思想影響下形成的迫靖,少許牽強(qiáng)。說起組件化兴使,不得不聊一點(diǎn)系宜。開始學(xué)習(xí)React,發(fā)現(xiàn)到處都是js发魄,連HTML標(biāo)簽也用js編寫盹牧,會覺得變扭俩垃,但真正做項(xiàng)目寫慣了,豁然感覺汰寓,這么寫比Vue更直白口柳,更爽。當(dāng)然也正是因?yàn)榻M件化有滑,React的難度比Vue大跃闹,比如ES6的類組件,什么高階函數(shù)啊毛好,入門過程比較漫長望艺。

  • 代碼風(fēng)格
    Vue文件把html\js\css按照三塊進(jìn)行組織,這種風(fēng)格把數(shù)據(jù)和視圖分開的很直接肌访,而React就一個(gè)JS找默,html部分只是Render函數(shù)的返回值(JSX),似乎感覺分離吼驶,但似乎有合在一起惩激。所以站在代碼風(fēng)格角度Vue的感覺更合理,但站在組件化的角度React的合并又更貼切蟹演。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末咧欣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子轨帜,更是在濱河造成了極大的恐慌渐溶,老刑警劉巖咙崎,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肘迎,死亡現(xiàn)場離奇詭異镀岛,居然都是意外死亡查描,警方通過查閱死者的電腦和手機(jī)肖抱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門软棺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猴誊,“玉大人阁将,你說我怎么就攤上這事膏秫。” “怎么了做盅?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵缤削,是天一觀的道長。 經(jīng)常有香客問我吹榴,道長亭敢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任图筹,我火速辦了婚禮帅刀,結(jié)果婚禮上让腹,老公的妹妹穿的比我還像新娘。我一直安慰自己扣溺,他們只是感情好骇窍,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锥余,像睡著了一般腹纳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哈恰,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天只估,我揣著相機(jī)與錄音,去河邊找鬼着绷。 笑死蛔钙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荠医。 我是一名探鬼主播吁脱,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼彬向!你這毒婦竟也來了兼贡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤娃胆,失蹤者是張志新(化名)和其女友劉穎遍希,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體里烦,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凿蒜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了胁黑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片废封。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丧蘸,靈堂內(nèi)的尸體忽然破棺而出漂洋,到底是詐尸還是另有隱情,我是刑警寧澤力喷,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布刽漂,位于F島的核電站,受9級特大地震影響冗懦,放射性物質(zhì)發(fā)生泄漏爽冕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一披蕉、第九天 我趴在偏房一處隱蔽的房頂上張望颈畸。 院中可真熱鬧乌奇,春花似錦、人聲如沸眯娱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽徙缴。三九已至试伙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間于样,已是汗流浹背疏叨。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留穿剖,地道東北人蚤蔓。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像糊余,于是被迫代替她去往敵國和親秀又。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容