React类组件setState后console.log无法获取state更新值的原因
核心原因
React 类组件中的 this.setState 是异步批量执行的,调用该方法时不会立刻同步修改 this.state 上的属性值,只会把本次状态更新请求加入更新队列,等当前同步执行上下文里的所有代码全部运行完毕后,React 才会统一合并处理队列里的状态更新,之后再触发重渲染流程。
示例代码的实际执行顺序
- 类实例化阶段执行
constructor,初始化state.foo = false,打印第一行结果false - 首次挂载执行
render方法,打印Render lifecycle - 挂载完成进入
componentDidMount生命周期,先打印componentDidMount() lifecycle - 执行
this.setState({ foo: true }),仅将foo更新为true的任务加入队列,此时this.state本身没有任何变化 - 紧接着执行第二句
console.log(this.state.foo),读取到的还是更新前的旧state值,因此打印结果仍是false - 等
componentDidMount内所有同步代码执行完成,React才会处理队列中的更新任务,将state.foo修改为true,再触发一次render执行重渲染
获取更新后状态值的正确写法
类组件的setState支持传入第二个回调函数参数,该回调会在状态更新落地、组件完成重渲染后触发,此时可以准确拿到更新后的最新state:
componentDidMount() { console.log('componentDidMount() lifecycle'); // 第二个参数为更新完成后的回调 this.setState({ foo: true }, () => { // 此处打印结果为更新后的true console.log(this.state.foo); }); // 同步位置的console永远拿不到刚set的新值 console.log(this.state.foo); }
补充说明:React 17及更早版本中,仅React管控的生命周期、合成事件内的setState会走批量异步逻辑,原生DOM事件、setTimeout/setInterval等异步回调里的setState会同步更新state;React 18之后所有场景下的setState默认都会走批量异步更新。你当前在
componentDidMount生命周期内调用setState的场景,全版本React都会命中批量更新规则,因此同步位置读取不到更新后的值。
内容的提问来源于stack exchange,提问作者Emma Earl Kent
相关产品推荐
相关产品推荐

