-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
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
第 18 题:React 中 setState 什么时候是同步的,什么时候是异步的? #17
Comments
这里所说的同步异步, 并不是真正的同步异步, 它还是同步执行的。 这里的异步指的是多个state会合成到一起进行批量更新。 希望初学者不要被误导 |
你是想说明什么,没太明白。 你的意思难道是从你截图给的这个可以看出reactsetState是或者部分是异步的? ---补充--- 或者你的意思难道是标题是《何时setState是异步的》, 就断定 “setState确实可能是异步的” |
这道题和19题有些类似。#18 (comment) |
我们平时写的时候就当它是异步进行就好了。 |
我的个人观点是这样的对于同步或者是异步都可以进行控制的想要同步就同步想要异步就异步 |
@yygmind 被这问题吓到了,还好点进来看了,你做出了我放心的解释 |
React Dan Abramov 大佬的解释 |
由React控制的事件处理程序,以及生命周期函数调用setState不会同步更新state 。 |
单独的说同步异步没有意义,一般配合场景: |
异步更新,同步执行 |
React的setState本身并不是异步的,是因为其批处理机制给人一种异步的假象。 【React的更新机制】 生命周期函数和合成事件中:
原生事件和异步代码中:
总结: |
先说结论:如果是通过 上面的评论中说了很多 setState “异步”的情况。我这里补充一下“同步”的情况,下面的例子使用了 setTimeOut,组件最后显示结果是 class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.handleAddCount = this.handleAddCount.bind(this);
}
componentDidMount() {
setTimeout(this.handleAddCount, 1*1000);
}
handleAddCount() {
this.setState({
count: this.state.count + 11
});
this.setState({
count: this.state.count + 22
});
}
render() {
return <div>{this.state.count}</div>;
}
} 源码:从源码的角度来说,setState 的行为是“异步”还是“同步”取决于 React 执行 setState 方法时的 如果 ExecutionContext 为 0,表示当前没有正在进行的其他任务,则 setState 是“同步”的。React 源码地址:https://github.com/facebook/react/blob/b53ea6ca05d2ccb9950b40b33f74dfee0421d872/packages/react-reconciler/src/ReactFiberWorkLoop.js#L411 ①注意这里的 |
setState是同步还是异步?
此处
|
我们知道Promise.then(),setTimeout是异步执行. 从js执行来说, setState肯定是同步执行. 所以这里讨论的同步和异步并不是指setState是否异步执行, 而是指调用setState之后this.state能否立即更新. |
setState是异步的,setState之后,取state中的值并不一定是最新更新的值。 |
react 18 发布之后,估计要对不同版本不同模式进行不同的回答了 |
为什么setTimeout里面的setState就不能进行批处理?如果批处理会有什么异常,望解答。 |
看了这段应该就清晰很多了。 react 会在执行前加一个“锁”来标记是否需要批处理, 如上,react加了锁之后立刻就释放了,然后才会执行setTimeout里的setState, 也就是说setTimeout和原生事件会脱离react的控制。 只有在react控制下才会存在批处理,setState才会有“异步”效果。
|
在最新的版本里面,React已经默认auto batch updating了 |
针对这个问题,大家默认讨论版本是react15, fiber之前 |
【高能预警:你懂得越多,你不懂得更多】
1.
|
这里的 “控制” 是指什么呢?如果脱离控制后会发生什么呢? |
setTimeout/setInterval调用并不是同步setState,也是异步的 在线例子:https://stackblitz.com/edit/react-ts-sqs8mw?file=App.tsx |
@janyin clickHandler 是通过 react 合成事件调用的呀 |
是合成事件,但是里面用的是setTimeout |
这个issue之前是没问题的。React18后setState全部都是异步的,所以不需要再分情况讨论,包括原生DOM事件和setTimeout之类的。 另外我觉得讨论这个问题没多大意义,因为setState本身设计出来就是异步的,要同步的访问state就用第二个参数回调访问啊。不然别人设计出第二个参数干嘛。
|
这个是原生事件的例子: https://stackblitz.com/edit/react-ts-kabj1e?file=index.tsx,App.tsx
|
噢噢 是我这边的问题,确实是因为 react18 的问题 |
如果setState 在React 能够控制的范围被调用,它就是异步的。 例如:合成事件处理函数, 生命周期函数, 此时会进行批量更新, 也就是将状态合并后再进行DOM 更新。 如果setState 在原生JavaScript 控制的范围被调用,它就是同步的 |
|
在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 机制
The text was updated successfully, but these errors were encountered: