Reactjs vs. Vuejs


紀俊,從事Web前端開發工作,2016年加入騰訊OMG廣告平台產品部,喜歡研究前端技術框架。

這里要討論的話題,不是前端框架哪家強,因為在 Vue 官網就已經有了比較全面客觀的介紹,並且是中文的。

上圖是二月份前端框架排名,React 位居第一,Vue 排名第三。還清晰記得,16 年十月份該 showcase 首頁並未看到 Vue,如今已有 40000+ stars,那時的 React 也差不多這個成績,可見 Vue 2.0 有多受關注,而排名第二的 Angular 當時位居第一,短短數月 React、Vue 都有比較好的成績,而 Angular 的 stars 沒有明顯增長,是否可以斷章取義,Angular 正在慢慢地退出這個舞台。

對於近期關注度最高的 React 和 Vue,想在這里談談兩個框架在開發風格上的差異。Vue 升級到2.0之后新增了很多 React 原有的特性,我的理解是 Vue 在這些方面對 React 的肯定和致敬,下面將在幾個細節上作對比。

Vue更容易上手

Vue 更容易上手!這是真的嗎?我書讀的少,作者是想支持國產嗎?

Vue 的語法很自由,比如:

  • 前期不需要認識復雜的生命周期函數,可能只關心 mounted 和 Vue.nextTick(保證 this.$el 在 document 中)

  • 熟悉的前端模板

  • 父子組件間通信更靈活

  • slot,可以大尺度地擴展組件(但也不要過度使用哦)

  • v-model,mvvm 的方式處理表單更方便

  • 官網中文文檔(哈哈,不得不承認)

從入門學習一個框架的角度看,少一些規則多一些自由空間,門檻會低些。

表單在 React 中的蛋疼之處

React 和 Vue 如何拿 input 的 value,先上代碼

Reactjs

class Demo extends React.Component{ constructor(props){ super(props) this.state={ inputA: '', inputB: '' } } _onChangeA(e){ this.setState({ inputA: e.target.value }) } _onChangeB(e){ this.setState({ inputB: e.target.value }) } render() { return ( <div> <input onChange={this._onChangeA.bind(this)} value={this.state.inputA} /> <input onChange={this._onChangeB.bind(this)} value={this.state.inputB} /> </div> ); } }; ReactDOM.render( <Demo/>, document.getElementById('container') ); 

Vuejs

<div id="demo"> <input v-model="inputA" :value="inputA"/> <input v-model="inputB" :value="inputB" /> <button @click="show" > show </button> </div> new Vue({ el: '#demo', data: { inputA: '', inputB: '' } }) 

Vue 進行表單處理的方式是不是更簡潔,由於 v-model 屬性支持數據雙向綁定,說白了就是(value 的單向綁定 + onChange 事件監聽)的語法糖,但這個味道還不錯吧,比起在 React 中需要綁定多個 onChange 事件確實要方便得多。

JSX vs Templates

剛接觸 React,因為用慣了javascript 模板引擎,一直堅信視圖與功能邏輯分離是正確的選擇,突然看到 JSX 把 html 寫在 js 里,內心是拒絕的!

Facebook 官方好像知道大家對 JSX 有偏見,在文檔一開始就給出解釋

We strongly believe that components are the right way to separate concerns rather than “templates” and “display logic.” We think that markup and the code that generates it are intimately tied together. Additionally, display logic is often very complex and using template languages to express it becomes cumbersome.

在這里結合我的理解翻譯一下, React 團隊堅信一個組件的正確用途是 “separate concerns”,而不是前端模板或者展示邏輯。我們認為前端模板和組件代碼是緊密相連的。另外,模板語言經常讓展示的邏輯變得更復雜。

剛開始沒弄明白什么是 “separate concerns”,其實現在也… Facebook 可能是在強調組件應該從功能上去抽象定義,而不僅僅從視覺上區分。

組件通信

Vue 組件向上通信可通過觸發事件,但在 Vue 2.0 廢棄 dispatch,建議使用global event bus。而大多初學者以為 React 只能靠調用父組件的 callback,並且這種方式遇到組件層次太深的時候簡直就是噩夢。其實 React 也可以通過事件通信來解決問題,只不過需要額外 coding 或調用第三方插件,而 Vue 的核心庫已實現了該功能。React 擁有豐富的生態圈,很多事情是大家一起完成的。

ref or props

父組件可通過 ref 定位子組件並調用它的 api,也可通過 props 傳遞數據,實現父組件通知子組件,ref 和 props 這兩種方式將決定組件的形態。在實際開發中,可能 Vue 先入為主,ref 也用的比較多,因為它在組件封裝力度上確實有優勢, api 可讓組件更抽象、更關注自身的功能,不受外界影響。而后來轉到 React 幾乎都是用 props 通信,一開始還以為是 React 的問題,甚至還得出了這樣的結論:React 組件像是 UI 組件,Vue 組件更接近對象。直到最近看了 Facebook 文檔,才發現另有蹊蹺。先看看之前用 Vue ,我是如何去創建一個列表(List)組件,並實現列表數據的新增和刪除,以及調用方式。

沒用過 ref 的同學,可以先看下文檔,不過看完下面代碼也能大概知道 ref 的作用。

Vuejs

<script src="https://unpkg.com/vue/dist/vue.js"></script> <div id="demo"> <input :value="input" v-model="input" /> <button @click="add" > add </button> <List ref="list" /> </div> var List = Vue.extend({ props: { list: { type: Array, default: function(){return []} } }, template:'<div><ul v-for="(item, index) in list"><li>{{item.name}} <i @click="deleteItem(item, index)">delete</i></li></ul></div>', data: function(){ return{ input: '' } }, methods: { addItem: function(name){ this.list.push({name: name}) }, deleteItem: function(item, index){ this.list.splice(index, 1) } } }) Vue.component('List',List) new Vue({ el: '#demo', data: { input: '' }, methods: { add: function(){ this.$refs.list.addItem(this.input) } } }) 

再看看 React 是怎么做的

class List extends React.Component{ _delete(index){ this.props.onDelete && this.props.onDelete(index) } render() { return ( <ul> { this.props.list.map((item, index)=>{ return ( <li key={index} > {item} <i onClick={this._delete.bind(this, index)}> delete </i> </li> ) }) } </ul> ); } }; class Page extends React.Component{ constructor(props){ super(props) this.state={ input: '', list: [] } } _bindChange(e){ this.setState({ input: e.target.value }) } _add(){ this.state.list.push(this.state.input) this.forceUpdate() } _delete(index){ this.state.list.splice(index, 1) this.forceUpdate() } render() { return ( <div> <input onChange={this._bindChange.bind(this)} value={this.state.input} /> <button onClick={this._add.bind(this)} > add </button> <List list={this.state.list} onDelete={this._delete.bind(this)} /> </div> ); } }; ReactDOM.render( <Page/>, document.getElementById('container') ); 

通過上面兩段代碼可以看出,在調用 List 組件的時候,React 比 Vue 復雜的多,不僅僅是多了 onChange,還有新增和刪除的邏輯,都必須在父組件中實現,這樣會導致項目中多處調用 List 組件,都必須實現這套相似的邏輯,而這套邏輯在 Vue 中已封裝在組件里,這也是為什么利用 ref 在封裝力度上有優勢,所以給我的感覺,React 比較關注組件的展示,而 Vue 比較關注功能。

細心的同學可能發現了,React也有 ref 屬性,它也可以讓父組件調用子組件的 api,但實際項目中卻很少看到,為什么大家都這么同步一致呢?我查了一下文檔,原來 Facebook 不推薦過度使用 ref

Your first inclination may be to use refs to “make things happen” in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to “own” that state is at a higher level in the hierarchy. See the Lifting State Up guide for examples of this.

官方還有個栗子,這里我也舉個比較常見的

基於上面的栗子,比如現在列表數據多啦!需要在列表頂部顯示有多少條數據!我們可以定義一個顯示條數的組件 Counts。

Vuejs

var bus = new Vue() var Counts = Vue.extend({ data: function(){ return{ count: 0 } }, template: '<span>{{count}}</span>', mounted: function(){ var self = this bus.$on('plus', function(){ self.count++ }) bus.$on('minus', function(){ self.count-- }) } }) Vue.component('Count', Count) 

Reactjs

let Counts = (props)=>{ return ( <span> {props.count} </span> ); } 

如按照 Vue 的實現方法(好吧!這里好像要黑 Vue,其實是我一開始的誤解),Counts 組件需監聽兩個事件(plus & minus),在事件回調中去更新條數,當 List 進行add() 或 delete() 需觸發plus / minus,且不說 Counts 組件復雜,這事件流也很難追溯,代碼放久看着吃力!但 React 把共享數據抽離了,父組件把this.state.list.length通過 props 傳入 Counts,這種方式邏輯更清晰,擴展能力更強。雖然像 React 這種,在不需要組件共享數據時,調用起來很繁瑣,調用 List 時add / delete 邏輯都要寫一遍,但業務的發展很難說,很多意想不到的情況都會發生,比如上面的栗子,后期指不定還要加一個分頁組件呢,所以我懸崖勒馬,以后不管在 Vue 還是 React,盡量少用 ref 調用子組件。當組件之間有共享數據時,該數據與操作該數據的邏輯,應該放在最接近它們的父組件,這樣組件的邏輯會更合理,更清晰!

最后,這兩個框架的路線有差異,Vue 偏向大而全,把很多特性都封裝進核心庫,React 則不同,React 核心庫只是 React 生態圈很小一部分,只負責 view 這個層面,其它事情都是由大家一起完成,所以 React 會有這么多插件。Reactjs 和 Vuejs 都是偉大的框架!

【騰訊雲的1001種玩法】 征文活動技術文章等你來讀! 點擊查看詳情


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM