We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Q: setState为什么有时候表现为同步,有时候表现为异步?
React组件根据props和state渲染UI,props由父组件传递进子组件,state由组件内部来维护。
props
state
setState() schedules an update to a component’s state object. When state changes, the component responds by re-rendering.
React官方文档的这句话解释了setState的作用:setState可以用来更新一个组件的state对象,当state变化时,组件会重新渲染UI。
setState
There is no guarantee that calls to setState will run synchronously, as they may eventually be batched together.
源码中对setState方法的注释:不能保证setState会同步执行,它们可能会进行批量更新。可以看下这个demo。
记住一点:React为提升性能,采取批量更新的策略。
简单来说batchingStrategy.isBatchingUpdates影响着setState是同步还是异步。当组件处于批处理事务中时,其值为true,setState表现为异步;反之,为false,setState表现为同步。
batchingStrategy.isBatchingUpdates
true
false
图中的internalInstance内部实例只组件在挂载过程中创建的ReactCompositeComponent实例。调用setState时,将partialState加入internalInstance的等待处理的状态列表,即_pendingStateQueue;如果传入了callback,则将callback加入internalInstance的等待处理的回调函数列表,即_pendingCallbacks。当batchingStrategy.isBatchingUpdates为true即处理批处理事务中时,将内部实例加入dirtyComponents队列。React会在批处理事务关闭时对dirtyComponents中的组件进行批量更新,表现为异步;当batchingStrategy.isBatchingUpdates为false时,则会进行一个完整的更新过程,表现为同步。
internalInstance
ReactCompositeComponent
partialState
_pendingStateQueue
callback
_pendingCallbacks
dirtyComponents
React会在自己可以控制的情况下采用批处理策略,比如如下几种情况
拿demo的中的代码来说:
demo
componentDidMount() { this.setState({ num: this.state.num + 1 }); this.setState({ num: this.state.num + 1 }); }
因为组件挂载采用了批处理策略,执行componentDidMount时,批处理事务仍然是打开的,那么此时batchingStrategy.isBatchingUpdates为true,不会更新组件的state。上面的代码即相当于
componentDidMount
internalInstance._pendingStateQueue.push(1,1)
那么当更新组件state时就把它更新为1了。
还有一种常见的setState方式,就是在事件回调中,请看这个demo 当我们点击按钮时,state仍然是每次只加1。
dispatchEvent: function(topLevelType, nativeEvent) { if (!ReactEventListener._enabled) { return; } var bookKeeping = TopLevelCallbackBookKeeping.getPooled( topLevelType, nativeEvent ); try { ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping); } finally { TopLevelCallbackBookKeeping.release(bookKeeping); } }
React实现了自己的syntetic事件,当事件触发时会调用上面的方法,我们看到了ReactUpdates.batchedUpdates,在这里会打开批处理事务,那么在这期间我们不管调用多少次setState,都会将内部实例加入dirtyComponents中进行批量更新,那么就和上面的demo是一样的情况了。
ReactUpdates.batchedUpdates
在浏览器的异步API和原生的DOM事件中setState会表现为同步,如setTimeout, setInterval, promise.then, addEventListener。 因为浏览器是单线程,非阻塞的,主线程执行的是函数调用栈顶的执行上下文中的代码,当遇到异步API时,会将其上下文加入到任务队列或微任务队列中。当执行栈为空时,会先将微任务队列中的代码执行完,然后执行任务队列中的代码。所以,当在这些异步API的回调中调用setState时,组件不会处于批处理过程中,batchingStrategy.isBatchingUpdates为false,表现为同步。
setTimeout, setInterval, promise.then, addEventListener
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Q: setState为什么有时候表现为同步,有时候表现为异步?
setState
React组件根据
props
和state
渲染UI,props
由父组件传递进子组件,state
由组件内部来维护。React官方文档的这句话解释了
setState
的作用:setState
可以用来更新一个组件的state
对象,当state
变化时,组件会重新渲染UI。源码中对
setState
方法的注释:不能保证setState
会同步执行,它们可能会进行批量更新。可以看下这个demo。记住一点:React为提升性能,采取批量更新的策略。
setState流程
简单来说
batchingStrategy.isBatchingUpdates
影响着setState
是同步还是异步。当组件处于批处理事务中时,其值为true
,setState
表现为异步;反之,为false
,setState
表现为同步。图中的
internalInstance
内部实例只组件在挂载过程中创建的ReactCompositeComponent
实例。调用setState
时,将partialState
加入internalInstance
的等待处理的状态列表,即_pendingStateQueue
;如果传入了callback
,则将callback
加入internalInstance
的等待处理的回调函数列表,即_pendingCallbacks
。当batchingStrategy.isBatchingUpdates
为true
即处理批处理事务中时,将内部实例加入dirtyComponents
队列。React会在批处理事务关闭时对dirtyComponents
中的组件进行批量更新,表现为异步;当batchingStrategy.isBatchingUpdates
为false
时,则会进行一个完整的更新过程,表现为同步。setState表现为异步的情况
React会在自己可以控制的情况下采用批处理策略,比如如下几种情况
生命周期函数中调用setState
拿
demo
的中的代码来说:因为组件挂载采用了批处理策略,执行
componentDidMount
时,批处理事务仍然是打开的,那么此时batchingStrategy.isBatchingUpdates
为true
,不会更新组件的state
。上面的代码即相当于那么当更新组件
state
时就把它更新为1了。事件回调中调用setState
还有一种常见的
setState
方式,就是在事件回调中,请看这个demo当我们点击按钮时,
state
仍然是每次只加1。React实现了自己的syntetic事件,当事件触发时会调用上面的方法,我们看到了
ReactUpdates.batchedUpdates
,在这里会打开批处理事务,那么在这期间我们不管调用多少次setState
,都会将内部实例加入dirtyComponents
中进行批量更新,那么就和上面的demo是一样的情况了。setState表现为同步的情况
在浏览器的异步API和原生的DOM事件中
setState
会表现为同步,如setTimeout, setInterval, promise.then, addEventListener
。因为浏览器是单线程,非阻塞的,主线程执行的是函数调用栈顶的执行上下文中的代码,当遇到异步API时,会将其上下文加入到任务队列或微任务队列中。当执行栈为空时,会先将微任务队列中的代码执行完,然后执行任务队列中的代码。所以,当在这些异步API的回调中调用
setState
时,组件不会处于批处理过程中,batchingStrategy.isBatchingUpdates
为false
,表现为同步。The text was updated successfully, but these errors were encountered: