2.React原理
# 1.函数式编程
一种编程范式,概念比较多
纯函数
不可变值
# 2.vdom和diff
h函数
vnode数据结构
patch函数
只比较同一层级,不跨级比较
tag不相同,则直接删掉重建,不再深度比较
tag和key,两者都相同,则认为是相同节点,不再深度比较
Vue2.x Vue3.0 React三者实现vdom细节都不同
核心概念和实现思路,都一样
面试主要考察后者,不用全部掌握细节
# 3.JSX本质是什么
JSX等同于Vue模板
Vue模板不是html
JSX也不是JS
https://www.babeljs.cn/
// JSX 基本用法
const imgElem = <div id="div1">
<p>some text</p>
<img src={imgUrl}/>
</div>
// JSX style
const styleData = { fontSize: '30px', color: 'blue' }
const styleElem = <p style={styleData}>设置 style</p>
// JSX 加载组件
const app = <div>
<Input submitTitle={onSubmitTitle}/>
<List list={list}/>
</div>
// JSX 事件
const eventList = <p onClick={this.clickHandler}>
some text
</p>
// JSX list
const listElem = <ul>{this.state.list.map((item, index) => {
return <li key={item.id}>index {index}; title {item.title}</li>
})}</ul>
// 总结
React.createElement('div', null, [child1, child2, child3])
React.createElement('div', {...}, child1, child2, child3)
React.createElement(List, null, child1, child2, '文本节点')
// h 函数
// 返回 vnode
// patch
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
React.createElement即h函数,返回vnode
第一个参数,可能是组件,也可能是html tag
组件名,首字母必须大写(React规定)

# 4.合成事件
所有事件挂载到document上
event不是原生的,是SyntheticEvent合成事件对象
和Vue事件不同,和DOM事件也不同
1. event 是 SyntheticEvent ,模拟出来 DOM 事件所有能力
2. event.nativeEvent 是原生事件对象
3. 所有的事件,都被挂载到 document 上
4. 和 DOM 事件不一样,和 Vue 事件也不一样
2
3
4

# 4.1 为何要合成事件机制
更好的兼容性和跨平台
挂载到document,减少内存消耗,避免频繁解绑
方便事件的统一管理(如事务机制)
# 5.setState batchUpdate
有时异步(普通使用),有时同步(setTimeout、DOM事件)
有时合并(对象形式),有时不合并(函数形式)
后者比较好理解(像Object.assign),主要讲解前者
# 5.1 setState主流程


# 5.2 batchUpdate机制
//此时setState相当于普通的异步
class ListDemo extends React.Component {
constructor(props) {...}
render() {...}
increase = ()=>{
//开始:处于 batchUpdate
// isBatchingUpdates = true
this.setState({
count:this.state.count + 1
})
//结束
//isBatchingUpdates = false
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
//模拟setTimeout下的batchUpdates机制,此时setState相当于同步
class ListDemo extends React.Component {
constructor(props) {...}
render() {...}
increase = ()=>{
//开始:处于 batchUpdate
// isBatchingUpdates = true
setTimeout(()=>{
//此时isBatchUpdates是false
this.setState({
count:this.state.count + 1
})
})
//结束
//isBatchingUpdates = false
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//模拟DOM事件下的batchUpdates机制,此时setState相当于同步
componentDidMount() {
//开始:处于 batchUpdate
//isBatchingUpdates = true
document.body.addEventListener('cliçk', ()={
//此时 isBatchingUpdates 是 false
this.setState({
count:this.state.count + 1
})
console.log('count in body event', this.state.count)
})
//结束
//isBatchingUpdates = false
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 5.2.1 setState是同步还是异步
setState无所谓异步还是同步
看是否能命中batchUpdate机制
判断isBatchingUpdates
# 5.2.2 哪些能命中batchUpdate机制
生命周期(和它调用的函数)
React中注册的时间(和它调用的函数)
React可以“管理”入口
# 5.2.3 哪些不能命中batchUpdate机制
setTimeout setInterval等(和它调用的函数)
自定义的DOM时间(和它调用的函数)
React“管不到”的入口
# 5.3 transaction(事务)机制
//transaction事务机制示例
class ListDemo extends React.Component {
constructor(props) {...}
render() {...}
increase = ()=>{
//开始:处于 batchUpdate
// isBatchingUpdates = true
//其他任何操作
//结束
//isBatchingUpdates = false
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*React源代码中给出的描述Transaction事务机制的工作原理的草图*/
wrappers (injected at creation time)
+ +
| |
+-----------------|--------|--------------+
| v | |
| +---------------+ | |
| +--| wrapper1 |---|----+ |
| | +---------------+ v | |
| | +-------------+ | |
| | +----| wrapper2 |--------+ |
| | | +-------------+ | | |
| | | | | |
| v v v v | wrapper
| +---+ +---+ +---------+ +---+ +---+ | invariants
perform(anyMethod) | | | | | | | | | | | | maintained
+----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
| | | | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
| +---+ +---+ +---------+ +---+ +---+ |
| initialize close |
+-----------------------------------------+
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//transaction使用示例
transaction.initialize = function() {
console.log('initialize')
}
transaction.close = function() {
console.log('close')
}
function method(){
console. log( 'abc' )
}
transaction.perform(method)
//依次输出'initialize'、'abc'、'close'
2
3
4
5
6
7
8
9
10
11
12
13
14
# 6.组件渲染过程
JSX如何渲染为页面
setState之后如何更新页面
面试考察全流程
# 6.1 前情回顾
# 6.1.1 Vue组件渲染和更新过程
Vue2版本示意图

Vue3版本示意图

# 参考链接
# 6.1.2 JSX本质和vdom
JSX即createElement函数
执行生成vnode
patch(elem,vnode)和patch(vnode,newVnode)
# 6.1.3 dirtyComponents

# 6.2 正式内容
# 6.2.1 组件渲染过程
props state
render()生成vnode
patch(elem,vnode)
# 6.2.2 组件更新过程
setState(newState) --> dirtyComponents(可能有子组件)
render()生成newVnode
patch(vnode,newVnode)
# 6.2.3 更新的两个阶段
上述的patch被拆分为两个阶段:
- reconciliation阶段 - 执行diff算法,纯JS计算
- commit阶段 - 将diff结果渲染DOM
# 6.2.4 可能会有性能问题
JS是单线程,且和DOM渲染共用一个线程
当组件足够复杂,组件更新时计算和渲染都压力大
同时若再有DOM操作需求(动画,鼠标拖拽等),将卡顿
# 6.2.5 解决方案-fiber
将reconciliation阶段进行任务拆分(commit无法拆分)
DOM需要渲染时暂停,空闲时恢复
window.requestIdleCallback
# 6.2.6 关于fiber
React内部运行机制,开发者体会不到
了解背景和基本概念即可