不吹不黑比对下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总不过度~~~