react setState是同步还是异步(面试真题)

setState通常是异步的,但在某些情况下会表现出同步行为。

主要分类

  1. 异步的情况(大部分场景)
    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

  1. 同步的情况
    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不一致

支持并发模式:为未来的并发特性做准备

如何获取更新后的值?

  1. 使用回调函数
    javascript
    this.setState({ count: newValue }, () => {
    console.log('更新后的值:', this.state.count);
    });
  2. 使用componentDidUpdate
    javascript
    componentDidUpdate(prevProps, prevState) {
    if (prevState.count !== this.state.count) {
    console.log('count更新了:', this.state.count);
    }
    }
  3. 使用useEffect(函数组件)
    javascript
    useEffect(() => {
    console.log('count更新了:', count);
    }, [count]);
    函数组件中的useState
    函数组件中的setState行为类似:

在事件处理函数中:异步批量更新

在异步代码中:在React 18+中默认也是批量更新

总结
场景 React 17及以前 React 18+
React事件 异步(批量) 异步(批量)
setTimeout等 同步 异步(批量)
原生事件 同步 异步(批量)
最佳实践: 始终假设setState是异步的,通过回调函数或useEffect获取更新后的状态。

posted @ 2026-01-14 20:14  疯狂的yang  阅读(2)  评论(0)    收藏  举报