# React原理
- 可以更深入理解react的内部实现原理
- 加深对react的理解
- 更高效的基于react开发业务代码
- 本文主要针对react核心知识点做一个总结
- 面试
1. 虚拟DOM(virtual document)
像reactjs、vuejs都是基于vdom进行二次开发框架(二者只是虚拟dom的定义属性不同)。那么为什么不约而同都采用这样一种方案?
- 浏览器在进行页面加载的时候,除了需要对dom树,cssom树进行解析,最后渲染,对于dom树节点少的来说,增删改查,整个html结构的变化,所带来的性能消耗可以忽略不计,然而现代网站这种现象基本不存在,因此,构建一个中大型网站来说,频繁的遍历,更新,操作dom,性能开销会很大的,而采用虚拟dom(js对象)来映射真实dom,将是更高效的方案
- 操作dom,需要获取当前节点,这中间可能会涉及样式、文档内容等变化、甚至增加或者消除,代码量比较大而且难于维护,虚拟dom带来的优势可以通过状态来控制视图,通过状态值的改变反映在页面上,对于开发维护来说更高效
- 虚拟dom可以组件化的形式进行二次封装开发,复用性更好。
例子
2. 模板编译
reactjs拥有自己的模板编译语法即通过jsx语法通过render函数返回vdom,这里也比较下vue编译模板<template></template>
下面是babel转译后的js对象构成
3. 虚拟dom渲染
- vdom对象有了就需要对这些对象进行更深入操作,reactjs采用深度优先遍历的法则
- 根据这些vdom对象不同的type类型,针对创建不同的节点
switch (vdom.tag) {
case HostComponent:
// 创建或更新 dom
case HostText:
// 创建或更新 dom
case FunctionComponent:
// 创建或更新 dom
case ClassComponent:
// 创建或更新 dom
}
2
3
4
5
6
7
8
9
10
11
- 组件化创建虚拟dom
switch (vdom.tag) {
case FunctionComponent:
const childVdom = vdom.type(props);
render(childVdom);
//...
case ClassComponent:
const instance = new vdom.type(props);
const childVdom = instance.render();
render(childVdom);
//...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
- react内部执行diff算法,最优化更新虚拟节点的创建
4. 视图状态机
react 是通过 setState 的 api 触发状态更新的,更新以后就重新渲染整个 vdom。 而 vue 是通过对状态做代理,get 的时候收集以来,然后修改状态的时候就可以触发对应组件的 render 了。
举个例子
从触发setState
节点开始,先往上找到root最顶层根元素,然后往下根据已存在属性拷贝一份新的fiber
,直到触发setState
节点,再往下遍历调用子元素render
,中间可以根据shouldComponentUpdate
等方法跳过
多了一个往上找直到root开始遍历(因为是fiber链表结构没有层级概念,依然用树的那一套就会导致渲染重复),并且父、祖父元素都拷贝一份新fiber
的步骤
React
自从16.8开始使用了 fiber
架构
fiber
使用了链表结构串联来虚拟dom树,主要的三个参数:child(子)、sibling(下一个兄弟)、return(父)
fiber
遍历过程就是找第一个元素一直找到底,然后找兄弟,没兄弟了往上
这个阶段分为两块,往下的过程是一些调用render
或者克隆一个fiber
节点的操作,往上的过程是生成effect
和updateQueue
更新内容的操作
假如在Text2
内触发setState
:
给Text2
标记更新字段lanes: 1
,并一直往上找,找到root
,并给沿途所以父节点设置childLanes: 0
,然后从root根节点开始遍历
当遍历到
lanes: 0
的时候:childLanes: 0
表示子孙元素没有变动直接跳过,也等于跳过了diff
childLanes: 1
就只是从之前的fiber
克隆一个新的fiber
节点
当遍历到
lanes: 1
的时候- 如果
shouldComponentUpdate
或类似的操作不更新,则走到上面lanes: 0
的流程 - 调用
render
生成新的fiber
- 如果
当到达最底部没有子元素的时候,开始compile
生成updateQueue
节点然后重复上面步骤(叶子节点为没有子元素的节点)叶子节点->兄弟->父->子->叶子
,最终回到root
结束
然后commit
阶段,这时候有个Effect
链表(Effect
链表只有变动的节点),遍历Effect
拿到节点的updateQueue
更新了哪些内容,将updateQueue
渲染到dom上
5. fiber架构
- Fiber是react团队定义的一种数据结构(JS对象),一个dom节点或者组件对应一个fiber对象
- Fiber节点之间构成 单向链表 结构, 以实现前文提到的几个特性: 更新可暂停/恢复、可跳过、可设优先级.
见上图示例
6. 总结
- react 和 vue 都是基于 vdom 的前端框架,之所以用 vdom 是因为可以精准的对比关心的属性,而且还可以跨平台渲染。
- 学习react构建 (opens new window)