react setState是同步还是异步(面试真题)
setState通常是异步的,但在某些情况下会表现出同步行为。
主要分类
- 异步的情况(大部分场景)
javascript
class Example extends React.Component {
state = { count: 0 };
handleClick = () => {
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 输出 0,不是 1
};
}
异步场景包括:
React合成事件(onClick、onChange等)
React生命周期函数
React的批量更新机制会合并多个setState
- 同步的情况
javascript
handleClick = () => {
setTimeout(() => {
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 输出 1,是同步的
}, 0);
};
同步场景包括:
setTimeout、setInterval回调
原生DOM事件监听
Promise.then()
async/await
React 18的变化
React 17及以前
在React事件处理中:批量更新(异步)
在宏任务/微任务中:同步更新
React 18+
所有更新默认都是批处理的(异步),包括setTimeout、Promise等
需要同步更新时,可以使用 ReactDOM.flushSync()
javascript
import { flushSync } from 'react-dom';
handleClick = () => {
flushSync(() => {
this.setState({ count: 1 });
});
console.log(this.state.count); // 输出 1
};
为什么设计成异步?
性能优化:合并多个setState,避免频繁re-render
保证一致性:避免中间状态导致UI不一致
支持并发模式:为未来的并发特性做准备
如何获取更新后的值?
- 使用回调函数
javascript
this.setState({ count: newValue }, () => {
console.log('更新后的值:', this.state.count);
}); - 使用componentDidUpdate
javascript
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
console.log('count更新了:', this.state.count);
}
} - 使用useEffect(函数组件)
javascript
useEffect(() => {
console.log('count更新了:', count);
}, [count]);
函数组件中的useState
函数组件中的setState行为类似:
在事件处理函数中:异步批量更新
在异步代码中:在React 18+中默认也是批量更新
总结
场景 React 17及以前 React 18+
React事件 异步(批量) 异步(批量)
setTimeout等 同步 异步(批量)
原生事件 同步 异步(批量)
最佳实践: 始终假设setState是异步的,通过回调函数或useEffect获取更新后的状态。

浙公网安备 33010602011771号