本篇文章将从动态绑定、渲染更新、逻辑复用、全局状态管理来比较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》