本篇文章将从动态绑定、渲染更新、逻辑复用、全局状态管理来比较vue和react的不同,从而给大家说明vue和react之间有哪些相同和不同点。

1.动态绑定: 1)在vue2中,使用了object.defineproperty()来做动态绑定。但是在处理数组和对象时,只能对初始渲染时已有的属性进行动态绑定,之后用户在对数组或者对象新增属性的时候,就需要用到vue的特殊API,而且在语言运行效率方面,通过Proxy的方式来给数据做动态绑定的效率更高,所以为了避免以上2个问题,vue3中采用了Proxy的方式来做动态绑定。 2)而在react中,数据被存储在state中,要想在模板中响应式更新数据必须通过setState的API对响应式数据显式重新赋值。所以并不会出现vue2中对数组和对象新元素响应式的适配问题。

2.渲染更新: 1)vue主要基于template和watcher的组件级更新,把每个更新任务分割得足够小,不需要使用到时间分片。在vue3中,更是把模板按照逻辑划分成静态区块和动态区块,更加减少了diff算法的时间。 2)react是不管在哪里调用setState,都是从根节点开始更新的,更新任务还是很大,需要使用到Fiber将大任务分割为多个小任务进行时间分片,可以中断和恢复,不阻塞主进程执行高优先级的任务。

3.逻辑复用: vue在逻辑复用方面有mixin、作用域插槽和vue3的function API。而react中所用到的工具有高阶组件、render props以及react16.8的Hook。下面我们来使用同一个示例监听鼠标位置的组件来比较一下: 1)vue的mixin:

const mousePositionMixin = {
  data() {
    return {
      x: 0,
      y: 0
    }
  },
  mounted(){
    window.addEventListener('mousemove', this.update)
  },
  destroyed(){
    window.removeEventListener('mousemove', this.update)
  },
  methods: {
    update(e){
      this.x = e.pageX
      this.y = e.pageY
    }
  }
}

当大量使用时: 响应式数据命名空间冲突。 模板数据来源不清晰。

2)react高阶组件是作为mixin的替代组件复用方式:

const Demo = withMousePosition({
  props: ['x', 'y'],
  template: `<div>Mouse position: x{{ x }} / y {{ y }} </div>`
})

高阶组件输入组件过多时: props命名空间冲突。 props来源不清晰。 额外的组件实例性能消耗。

3)vue作用域插槽:

<mouse v-slot="{x, y}">
    Mouse position: x {{x}} / y {{y}}
</mouse>

在mouse组件中实现监听逻辑,返回的x、y表示鼠标的位置,在插槽中显式。它的优点是:没有命名空间冲突,数据来源清晰。但是有额外的组件实例性能消耗。

4)vue3的function API:

function useMousePosition(){
  const x = value(0)
  const y = value(0)
  
  const update = e => {
    x.value = e.pageX
    y.value = e.pageY
  }
  
  onMounted(() => {
    window.addEventListener('mousemove', update)
  })
  
  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })
  
  return {x, y}
}
new Vue({
  template:`
    <div>
      Mouse position: x {{ x }} / y {{ y }}
    </div>
  `,
  setup(){
    const {x, y} = useMousePosition()
    return {x, y}
  }
})

调用useMousePosition时会获得x和y,进而在外层组件中使用。可以说解决了所有之前的问题:没有命名空间冲突、数据来源清晰、没有额外的组件性能消耗。

5)react的hook实现:

import { useState, useEffect } from 'react';

function useMousePosition() {
  const [x, setX] = useState(0);
  const [y, setY] = useState(0);
  const update = e => {
    setX(e.pageX)
    setY(e.pageY)
  }
  useEffect(() => {
    window.addEventListener('mousemove', update)
    return () => {
      window.removeEventListener('mousemove', update)
    };
  },[]);

  return {x, y};
}
function mousePosition() {
  const {x, y} = useMousePosition();
  return (
    <div>
      Mouse position: x {{ x }} / y {{ y }}
    </div>
  );
}

虽然vue3的functionAPI和react的hook都是把相关逻辑抽象到了一个函数当中,但是React Hook的运行机制与vue3的function API完全不同,react的Hook在每次组件重新渲染时都会执行一次,而vue3的数据是可以追踪的,function API只在组件初始化的时候执行一次。

参考: 掘金《走进React Fiber的世界》 bilibili《State of Vue》