React 原理
- 一种编程范式
- 纯函数
- 不可变值
# vdom 和 diff 算法
h 函数
vnode 数据结构
patch 函数
只比较同一层级,不跨级比较
tag 不相同,则直接删掉重建,不再深度比较
tag 和 key,两者都相同,则认为是相同节点,不再深度比较
# JSX 本质
- JSX 即 createElement 函数
- 执行生成 vnode
- patch(elem, vnode) 和 patch(vnode, newVnode)
# 合成事件
- 所有事件挂载到 document 上(React17版本开始,事件就不再绑定到 document上了,放到了root组件上)
- event 不是原生的,是 SyntheticEvent 合成事件对象
- 和 Vue 事件不同,和 DOM 事件也不同
# 为何要合成事件机制?
更好的兼容性和跨平台
载到 document,减少内存消耗,避免频繁解绑
方便事件的统一管理(如事务机制)
# React 17 事件绑定到 root
- React 16 绑定到 document
- React 17 事件绑定到 root 组件
- 有利于多个 React 版本并存,例如微前端
# setState 和 batchUpdate
- 有时异步(普通使用),有时同步 ( setTimeout、 DOM 事件)
- 有时合并(对象形式),有时不合并(函数形式)
- 后者比较好理解(像 Object.assign ),主要讲解前者
# 核心要点
# setState 主流程
# batchUpdate 机制
哪些能命中 batchUpdate 机制
- 生命周期(和它调用的函数)
- React 中注册的事件(和它调用的函数)
- React 可以“管理〞的入口
# transaction 事务机制
* <pre>
* wrappers (injected at creation time)
* + +
* | |
* +-----------------|--------|--------------+
* | v | |
* | +---------------+ | |
* | +--| wrapper1 |---|----+ |
* | | +---------------+ v | |
* | | +-------------+ | |
* | | +----| wrapper2 |--------+ |
* | | | +-------------+ | | |
* | | | | | |
* | v v v v | wrapper
* | +---+ +---+ +---------+ +---+ +---+ | invariants
* perform(anyMethod) | | | | | | | | | | | | maintained
* +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
* | | | | | | | | | | | |
* | | | | | | | | | | | |
* | | | | | | | | | | | |
* | +---+ +---+ +---------+ +---+ +---+ |
* | initialize close |
* +-----------------------------------------+
* </pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 组件渲染过程
- props state
- render0 生成 vnode
- patch (elem, vnode)
组件初始化 -> render 方法 -> 生成虚拟DOM -> React.DOM.render 方法 -> 真实DOM
组件更新 -> render 方法 -> 生成新的虚拟DOM -> diff算法 -> 定位出两次虚拟DOM的差异
render方法
# 组件更新过程
- setState(newState) --> dirtyComponents( 可能有子组件)
- render0 生成 newVnode
- patch(vnode, newVnode)
# 更新的两个阶段
- 上述的 patch 被拆分为两个阶段:
- reconciliation 阶段一执行 diff 算法,纯JS 计算
- commit 阶段-将 diff 结果渲染 DOM
# fiber 性能
# 可能会有性能问题
- JS是单线程,且和 DOM 渲染共用一个线程
- 当组件足够复杂,组件更新时计算和渲染都压力大
- 同时再有 DOM 操作需求(动画,鼠标拖拽等),将卡顿
# 解决方案 fiber
- 将 reconciliation 阶段进行任务拆分 (commit 无法拆分)
- DOM 需要渲染时暂停,空闲时恢复
- window.requestldleCallback
上次更新: 2022/08/14, 18:25:44