React 更新流程
此处介绍的 React 版本是 16.x。
想来大家应该知道,React 推崇数据 Immutable,当然这跟它自身有很大关系,它设计跟 Vue 完全不同,不是通过收集数据依赖去发现更新的,而是通过 re-render 去发现和更新自身。当然,React 推崇 Immutable 也是很有意义的,这篇文章 Immutable 详解及 React 中实践 #3 介绍了 Immutable 一些知识。
所以,React 要求我们使用 setState 和 hook 中 的 useState 的 setXXX(value) 去更新数据,进而触发更新。
React 的更新流程大概如下:
setState -> re-render(beginWork 递 & completeWork 归 )-> commit -> before mutation -> mutation -> layout
以上流程中, beginWork 和 completeWork 并没有先后顺序,请看下图(图片来源于卡老师的 React技术揭秘):
其中有很多知识点,如 Fiber, 生命周期的触发,数据更新等,这里就不详细说了。
Vue 更新流程
Vue 最令人称道的,应该是其响应式更新。配合模版食用,让人不禁发出:真香!
此处介绍的 Vue 的版本是 2.x 的。
从图中可以知道,Vue 通过首次渲染操作,触发了 Data 的 getter ,从而触发了依赖收集,为对应的数据创建 watcher,当数据发生更改时,也就是 setter 被触发了,那么,将会通知各个 watcher,在下一个 tick 时,会更新数据。更详细的数据绑定原理的知识,可以从这里从源码角度再看数据绑定.MarkDown 获得。
此处,需要注意的地方是,Vue 是通过渲染来触发数据的依赖收集的,也就是说,假如 Data 中有某些数据并没有在模版中使用的话,更新这些数据的时候,是不会触发更新的。
<template>
<p>
{{txtA}}
</p>
<p>
{{+new Date()}}
</p>
<div @click="changeA">
changeA
</div>
<div @click="changeB">
changeB
</div>
</template>
<script>
export default {
data() {
return {
txtA: 'hello',
txtB: 'hi'
}
},
methods: {
changeA() {
console.log('changeA~');
this.txtA = 'world';
},
changeB() {
console.log('changeB~');
this.txtB = 'guy';
}
}
}
</script>
如上代码,当 txtA 被赋新值后,页面的时间戳会发生变化,但 txtB 被赋新值,时间戳是不变化的,也就是并没有触发到更新。
不过这正是理想中的啊,没有在模版上用到的变量,当它的值发生变化时,就不应该更新视图。
补充一下 Vue 的初始化流程和更新流程:
初始流程
// 初始化props、methods、data、computed与watch
initState(vm)
template -> parse -> (AST) -> optimize -> generate -> (vNode) -> patch -> 映射到真实DOM
更新流程
watcher -> vNode -> patch -> 映射到真实DOM
React vs Vue 区别
从上面 React 和 Vue 的更新流程的介绍,应该可以得出他们对数据更新的区别之处:
- 获取数据更新的手段和更新的粒度不一样
Vue通过依赖收集,当数据更新时,Vue明确地知道是哪些数据更新了,每个组件都有自己的渲染 watcher ,掌管当前组件的视图更新,所以可以精确地更新对应的组件,所以更新的粒度是组件级别的。React会递归地把所有的子组件re-render一下,不管是不是更新的数据,此时,都是新的。然后通过diff 算法来决定更新哪部分的视图。所以,React的更新粒度是一个整体。
- 对更新数据是否需要渲染页面的处理不一样
- 只有依赖收集的数据发生更新,
Vue才会去重新渲染页面 - 只要数据有更新(
setState,useState等手段触发更新),都会去重新渲染页面(可以使用shouldComponentUpdate/PureComponent改善)
- 只有依赖收集的数据发生更新,