react和vue的区别是什么? 最讨厌问题,没有之一

238 阅读5分钟

首先,vue和React都是一个前端框架,用来减少开发人员对于纯dom操作的痛苦。提升开发体验。作为一个UI框架

相同点:

  1. 虚拟dom的概念
  2. 单向数据流

不同点:

  1. 模版不同
  2. 组件通信
  3. 响应式原理
  4. 虚拟节点的比较(组件更新)
  5. 事件机制

相同点详细阐述

虚拟dom

虚拟dom的存在,就是为了减少真实dom的增删改查,以提高性能

单向数据流

react和vue都采用的是单向数据流:这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。

不同点比较

模版不同

vue是模板编译,通过模板的形式,进行静态编译生成vnode实例。静态编译,速度比较快。

react是通过jsx语法,jsx实质上是一种动态的语言,所以很难进行编译优化。

组件通信

react 使用回调通信,vue使用事件emit进行通行。

现实开发中,我们是如何解决子组件中props中的数据的变更呢?

  1. 该状态只需要在子组件中改变
  2. 该状态确实需要在子无组件中更改,并应用到父组件中。

对于第一种情况,显然该状态属于子组件独有的,只是初始值来源于父组件,需要在子组件中保持自己的状态。

对于第二种情况,react建议遇到这种情况应该进行“状态提升”。将该状态提升到父亲组件。 vue使用事件的方式,除了这两种官方建议,是否还有别的方式呢?显而易见是有的: 可以通过事件总线来进行事件分发,用事件来触发更新 可以用状态管理机来进行处理,在vue中,有vux,在react中,一般使用mobx

响应式原理

vue2的响应式是在构建虚拟dom的过程中进行依赖收集,并对data函数中的数据进行遍历、使用Object.defineProtity进行重写拦截。以此进行数据更新的监听与分发。 这种方式有2个问题:1、需要递归处理所有数据;2.没有对数组进行遍历处理,导致无法监控到数组的变化,只对数组的部分函数进行了重写(push,pop,splice)等7个方法,需要调用这7个方法或者改变数组长度才能触发响应式,直接改变数组项不可行。

vu3将Object.defprotity优化为使用proxy进行代理。并使用懒代理的方式(第一次只代理一层,访问到该数据中的某一项为object的时候进行再进行代理)进行优化,减少初始时的递归。

react是基于状态机的响应式编程,需要对state进行手动更新,相当于是调用state手动触发更新。 原理是: react中的state保存在一个链表中,每次触发一个state相当于给链表中新增一个状态,组件渲染会在下一个渲染之前去state中获取到最新的状态。 所以在react hooks组件中,获得的状态都是上一次的。在一个方法中更新多次state的结果是一样的,只有最后一次生效。因为后面的setState会覆盖前面的setState.

虚拟节点的diff过程

vue的虚拟节点diff:

在vue中,虚拟节点的对比算法是双指针比较,先互相比较头尾节点之后依次向内比较,比较的逻辑如下步骤所示:

flowchart LR
A[Start] --> B{有oldVnode,\n没有新的vNode}
B -->|Yes| C[删除节点]
B -->|No| D{没有oldVnode,\n有新的vNode}
D -->|Yes| E[新建]
D -->|No| F{key和tag相同}
F -->|yes| G[更新节点]
G --> I{是文本}
I -->|yew| J[更新文本]
I -->|No| K[比较children]
F -->|No| H[删除旧节点,新建新节点并插入]

vue updateChildren:

  1. 比较首尾节点,两两比较
  2. 首首、尾尾相等,则进行更新
  3. 首尾、尾首相等,则移动
  4. 存储旧节点为key-map
  5. 新的节点在旧的中能找到,则进行patch,相等更新,不等替换、找不到插入(这一步保证了所有可复用的新节点都复用了)
  6. 循环结束后,批量删除需要删除和新增需要新增的

react Diff:

  1. oldFiber与newArray比较,如果oldFiber或者Array都已经比遍历结束,则跳出循环。
  2. oldFiber和newArray的当前值比较,如果是key相同,type相同,则用新的array的props更新新的fiber
  3. key相同,type不同,删除旧的,新增新的
  4. key type都不同,跳出循环

第二次比较:

  1. 只剩下旧的节点(删除旧节点)
  2. 只剩下新的节点(新增新节点)
  3. 都有剩下则进行下一步的处理:
  • 将旧的fiber用一个key-fiber的map存起来
  • 遍历新的数组,如果在旧的fiber中找到fiber,则利用旧的fiber并更新并删除key,否则新建
  • 删除map中剩余的key和fiber.(多余的)

不难发现,react从左到右,找不到相同的就开始处理剩下的复杂节点,vue是首尾同时开始找,找不到相同的再处理中间的复杂部分。 看起来是vue的算法更优秀一些。

react的fiber是单向链表,所以不可能能做到双向比较,至于什么时候改,那得看会不会有比较大的性能问题出现。

事件机制

在react中,有一个事件合成机制,最终所有的事件都会被绑定在document上,所以需要对事件进行冒泡拦截的时候,要特别处理好是原生事件还是react本身的事件。

vue和React的生态

打包构建能力