CodingMeUp / AboutFE

知识归纳、内容都在issue里
74 stars 14 forks source link

0、React源码底层分析 #1

Open CodingMeUp opened 6 years ago

CodingMeUp commented 6 years ago

1、使用ReactDom.render创建你的组件Component

2、创建ReactCompositeComponent对象让根元素包裹整个VDOM

3、开始挂载(mount)组件

4、开始批量更新(batch update)

5、事务包裹预处理UI并禁用浏览器相关的事件处理

6、事务更新队列返回的更新(updater)被赋值给实例、构造组件后创建了new ExampleApplication()、开始第一次接触React生态系统

7、发生行为componentWillMount、可以setState但是不会触发render(因为此时组件还没有被挂载)

8、订阅componentDidMount、被注入了事务队列、在很后面执行、在挂载系列操作执行完后才执行

9、调用组件中申明的render方法、第二次接触我们代码

10、基于ReactCompositeComponent的render方法获得的元素创建VDOM,所以VDOM是一个ReactDomElement、继续挂载

11、创建_Tag的HTML标签(复杂HTML标签封装)、更新DOM属性及创建子元素及挂载

12、更新DOM属性、这里是性能优化重要一环(diff差分对比算法探测属性的差异)

一、lastprops循环(检查nextProps对象里是否同prop,相同就跳过,因为会再nextProps循环中处理,重置样式的值,删除时间监听器,去除DOM属性名和属性值)

二、nextprops循环(检查prop是不是变化、也就是检查将来值和老值相同,相同跳过,对于样式,我们更新从lastprop到现在变化的部分值、添加事件监听器如onclick、根据事务传递下来确定DOM是否准备好来判断添加监听器的时间、处理完事件监听器、设置DOM属性和值)

13、组件本身的创建完了、子组件的创建

14、一种被称作markup的HTML生成、代替父容器的内容、还原UI并告知挂载准备好了、(调用componentDidMount)、清空批量更新并且处理脏组件

image

CodingMeUp commented 6 years ago

15、组件中setState继承自ReactComponent、在挂载组件的时候实例会接受一个React的更新队列作为updater的属性、setState传递的对象(partialState)执行enqueneUpdate、如果更新已经在进展中、则注入到dirtyComponents如果没有则初始化打开更新事务再注入到dirtyComponents

一、 每个组件都有自己的一组处于等待的”状态“的列表,当你在一次事务中调用 setState 方法,其实只是把那个状态对象注入一个队列里,它会在之后一个一个依次被合并到组件 state 中。调用此setState方法同时,你的组件也会被添加进 dirtyComponents 列表。

简单说: setState后判断批处理事务有没打开,无就打开,把受到影响的组件添加到dirtyComponents列表、调用ReactUpdates.flushBatchedUpdates的同时关闭事务、再处理dirtyComponents列表的中的组件(这里有排序、挂载的时候组件获得的序列整数[mount order]、父组件先挂载先更新)、根据提升批号updateBatchNumber避免重复更新同一个组件

16、关于更新组件

已经挂载后的组件执行再更新操作的时候、componentWillReceiveProps和shouldComponentUpdate方法会被调用、若这个更新有效那DOM会被更新、DIFF算法会生效、对复杂的实现往往会重写、componentWillUpdate不调用setState了、把componentDidUpdate压入队列、调用render方法拿到记过、判断组件是否需要被完全替换或者额外的更新、调用已经挂载后的组件执行再更新操作的时候、componentWillReceiveProps和shouldComponentUpdate方法会被调用、若这个更新有效那DOM会被更新、DIFF算法会生效、对复杂的实现往往会重写、componentWillUpdate不调用setState了、把componentDidUpdate压入队列、调用render方法拿到记过、判断组件是否需要被完全替换或者额外的更新、调用componentDidUpdate

image

CodingMeUp commented 4 years ago

第 18 题:React 中 setState 什么时候是同步的,什么时候是异步的? #17

这里所说的同步异步, 并不是真正的同步异步, 它还是同步执行的。

这里的异步指的是多个state会合成到一起进行批量更新。

在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state 。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。

原因: 在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。

注意: setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。

详细请看 深入 setState 机制