最近笔者在学习react的fiber,学习过程中不禁想到:为什么react需要fiber架构来优化,但是vue不需要fiber架构。
搜集了相关资料并学习后,觉得还蛮有意思,于是就写下来这篇文章来记录下这个问题,如有问题,欢迎指正。
目录
根本原因
这个问题最根本的原因:react和vue响应式实现方式的不同。
何为响应式
什么是响应式呢?让我们看看vue和react官网是如何解释的
vue官网:
react官网:
原生js实现
如果我们使用原生的js去让对应的视图发生变化,该如何实现呢?
- 获取到对应的dom
- 修改dom的值
react实现
使用setState去修改对应的值就行了,之后对应的视图展示会自动展示成刚才修改的值。
vue实现
直接修改对应state的值,之后对应的视图展示会自动展示成刚才修改的值。
react和vue如何实现响应式
视图更新流程
- 触发视图更新,根据变化生成新的虚拟dom树
- 新旧虚拟dom树对比,找出变化的部分(diff)
- 将变化的部分更新到真实的dom
我们来看官网是如何说的
vue响应式实现原理
官方文档原话:
“如何追踪变化:
当你把一个普通的 JavaScript 对象传入 Vue 实例作为
data
选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty
是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。”
简单来说就是对数据进行劫持(vue3使用的是Proxy):当该数据发生变化的时候,就知道该找谁,做什么。
react响应式实现原理
react状态改变需要setXXX来触发,当触发之后,会从《声明该state的组件(调用useState的组件)》开始,往下渲染(该组件&其子组件全部都要渲染)。
官方文档原话:
“一旦组件被初次渲染,您就可以通过使用set函数更新其状态来触发之后的渲染。更新组件的状态会自动将一次渲染送入队列。”
“与 props 不同,state 完全私有于声明它的组件。”
详见:渲染和提交 – React
想象一下,如果现在有一个虚拟dom树,在<SonA>组件中使用useState定义了状态a,<SonA>的子组件中只有<FourA>和<TwoA>使用了状态a。
之后我们在<FourA>中调用了setA(2)修改a的值,之后<SonA>以及它的所子组件都要重新渲染(红色部分)。
哪怕改变a的值之后只有<FourA>和<TwoA>会有更改,但是<SonA>为根节点的整个树都要重新渲染,是很浪费性能的。
区别
通过上面分析了vue和react视图更新原理,我们可以得到差别:
react通过setXXX这种触发更新的机制,没有办法像vue那样精确的知道具体是哪一个组件需要重新渲染,只能从父组件开始往下全部渲染,所以很消耗性能。
已知信息不足,造成了react的这种结果。
下图很好的总结出了他们的差别:
Fiber
关于react的fiber架构,可参考笔者的这篇文章,写的比较详细:从0到1,带你深入了解react fiber_Bule Guy的博客-CSDN博客
参考: