Open CodingMeUp opened 6 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 机制
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)、清空批量更新并且处理脏组件