setState 调用之后触发的生命周期 setState -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
异步更新的动机 批量更新
1 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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 import React from "react" ;import "./styles.css" ;export default class App extends React .Component { state = { count: 0 } increment = () => { console .log('increment setState前的count' , this .state.count) this .setState({ count: this .state.count + 1 }); console .log('increment setState后的count' , this .state.count) } triple = () => { console .log('triple setState前的count' , this .state.count) this .setState({ count: this .state.count + 1 }); this .setState({ count: this .state.count + 1 }); this .setState({ count: this .state.count + 1 }); console .log('triple setState后的count' , this .state.count) } reduce = () => { setTimeout (() => { console .log('reduce setState前的count' , this .state.count) this .setState({ count: this .state.count - 1 }); console .log('reduce setState后的count' , this .state.count) },0 ); } render ( ) { return <div> <button onClick={this .increment}>点我增加</button> <button onClick={this .triple}>点我增加三倍</button> <button onClick={this .reduce}>点我减少</button> </div> } }
如果每一次调用setState都直接触发完整生命周期,re-render将会带来性能问题.那么此时就需要异步更新,利用Event-Loop,等时机成熟,再把“攒起来”的 state 结果做合并,最后只针对最新的 state 值走一次更新流程。同步任务不结束就一直放入,最后只针对最新的 state 值走一次更新流程 ,这就是批量更新。
同步现象 本质上是由 React 事务机制和批量更新机制的工作方式来决定 setState调用时会判断内部 batchingStrategy.isBatchingUpdates标识状态来决定是立即更新,还是先放入更新队列,等待批量更新
在生命周期等位置需要开启批量更新,但是setTimeout是异步的,它执行时这个isBatchingUpdates标记已经放开了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 increment = () => { isBatchingUpdates = true console .log('increment setState前的count' , this .state.count) this .setState({ count: this .state.count + 1 }); console .log('increment setState后的count' , this .state.count) isBatchingUpdates = false }