关于React中setState同步或异步问题的理解

 更新时间:2021年11月12日 10:15:06   作者:火星飞鸟  
相信很多小伙伴们都一直在疑惑,setState 到底是同步还是异步。本文就详细的介绍一下React中setState同步或异步问题,感兴趣的可以了解一下

1. setState同步?异步?

在 React 的类式组件中,我们可以使用setState方法更新state状态。但有些时候使用setState之后,得不到最新的数据。

其实 React 中setState本身执行的过程和代码是同步的,只是因为 React 框架本身的性能优化机制而导致的。React 中合成事件和生命周期函数的调用顺序在更新之前,导致在合成事件和生命周期函数中无法立刻得到更新后的值,形成了异步的形式。

假如在一个合成事件中,循环调用了setState方法n次,如果 React 没有优化,当前组件就要被渲染n次,这对性能来说是很大的浪费。所以,React 为了性能原因,对调用多次setState方法合并为一个来执行。当执行setState的时候,state中的数据并不会马上更新。

前面已经说到,在 React 的合成事件和生命周期函数中直接调用setState,会表现出异步的形式。

除此之外,如果越过 React 的性能优化机制,在原生事件、setTimeout中使用setState,就会表现出同步的形式。

2. 表现为异步

1. React 合成事件

在 React 中直接使用的事件,如onChange、onClick等,都是由 React 封装后的事件,是合成事件,由 React 管理。那么由于性能优化的机制,在合成事件中直接调用setState,将表现出异步的形式。

如下代码,在合成事件onClick中,直接将state中的count加1,并在此之后打印count的值,结果第一次点击按钮时,会打印出0,而不是最新的1。

state = { count: 0 };
add = () => {
    this.setState({ count: this.state.count + 1 });
    console.log(this.state.count); // 0
};
render() {
    return (
        <>
            <div>当前计数:{this.state.count}</div>
            <button onClick={this.add}>add</button>
        </>
    );
}

2. 生命周期函数

生命周期函数也是由 React 所管理,在生命周期函数中直接调用setState,也会表现出异步的形式。

如下代码,在生命周期componentDidMount函数中,将state中的count加1,并在此之后打印count的值,结果打印出0,而不是最新的1。

state = { count: 0 };
componentDidMount() {
    this.setState({ count: this.state.count + 1 });
    console.log(this.state.count); // 0
}
render() {
    return (
        <>
            <div>当前计数:{this.state.count}</div>
            <button>add</button>
        </>
    );
}

3. 表现为同步

1. 原生事件

setState本身执行的过程是同步的,使用原生事件,绕过 React 的管理,将表现出同步的形式。

如下代码,通过id获取到 DOM 元素,用原生方法绑定点击事件。在点击事件中,将state中的count加1,并在此之后打印count的值,结果会打印最新的count值1。

state = { count: 0 };
componentDidMount() {
    const btn = document.getElementById('btn');
    btn.onclick = () => {
        this.setState({ count: this.state.count + 1 });
        console.log(this.state.count); // 1
    };
}
render() {
    return (
        <>
            <div>当前计数:{this.state.count}</div>
            <button id="btn">add</button>
        </>
    );
}

2. setTimeout

如下代码,在生命周期componentDidMount函数中写了一个定时器setTimeout,在setTimeout内部将state中的count加1,并在此之后打印count的值,结果会打印最新的count值1。

setState虽然也是写在生命周期componentDidMount函数中的,但并不是直接写在componentDidMount里,而是套了一层setTimeout。这样,setState就表现出同步的形式。

state = { count: 0 };
componentDidMount() {
    setTimeout(() => {
        this.setState({ count: this.state.count + 1 });
        console.log(this.state.count); // 1
    }, 0);
}
render() {
    return (
        <>
            <div>当前计数:{this.state.count}</div>
            <button>add</button>
        </>
    );
}

4. setState的第二个参数

无论setState的对象式写法,还是函数式写法,都有第二个参数,为可选的回调函数,这个回调函数在状态更新完毕、界面也更新后(render调用后)才被调用。

如下代码所示,setState虽然直接在componentDidMount中调用,但在setState的回调函数中打印count的值,得到了最新的值1,因为回调函数在状态更新完毕后才被调用,当然能得到最新的count了。

state = { count: 0 };
componentDidMount() {
    this.setState({ count: this.state.count + 1 }, () => {
        console.log(this.state.count); // 1
    });
}
render() {
    return (
        <>
            <div>当前计数:{this.state.count}</div>
            <button>add</button>
        </>
    );
}

到此这篇关于关于React中setState同步或异步问题的理解的文章就介绍到这了,更多相关React中setState同步或异步内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React Hook实现对话框组件

    React Hook实现对话框组件

    这篇文章主要为大家详细介绍了React Hook实现对话框组件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • React中进行条件渲染的实现方法

    React中进行条件渲染的实现方法

    React是一种流行的JavaScript库,它被广泛应用于构建Web应用程序,在React中,条件渲染是一个非常重要的概念,它允许我们根据不同的条件来呈现不同的内容,在本文中,我们将探讨React如何进行条件渲染,需要的朋友可以参考下
    2023-11-11
  • 浅谈react+es6+webpack的基础配置

    浅谈react+es6+webpack的基础配置

    下面小编就为大家带来一篇浅谈react+es6+webpack的基础配置。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • 关于antd tree和父子组件之间的传值问题(react 总结)

    关于antd tree和父子组件之间的传值问题(react 总结)

    这篇文章主要介绍了关于antd tree 和父子组件之间的传值问题,是小编给大家总结的一些react知识点,本文通过一个项目需求实例代码详解给大家介绍的非常详细,需要的朋友可以参考下
    2021-06-06
  • 手动用webpack搭建第一个ReactApp的示例

    手动用webpack搭建第一个ReactApp的示例

    本篇文章主要介绍了手动用webpack搭第一个 ReactApp的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • React SSR 中的限流案例详解

    React SSR 中的限流案例详解

    这篇文章主要介绍了React SSR 之限流,React SSR 毕竟涉及到了服务端,有很多服务端特有的问题需要考虑,而限流就是其中之一,本文会通过一个简单的案例来说明,为什么服务端需要进行限流,需要的朋友可以参考下
    2022-07-07
  • ReactNative实现的横向滑动条效果

    ReactNative实现的横向滑动条效果

    本文介绍了ReactNative实现的横向滑动条效果,本文结合示例代码给大家介绍的非常详细,补充介绍了ReactNative基于宽度变化实现的动画效果,感兴趣的朋友跟随小编一起看看吧
    2024-02-02
  • 浅析React 对state的理解

    浅析React 对state的理解

    state状态是组件实例对象身上的状态,不是组件类本身身上的,是由这个类缔造的实例身上的。这篇文章主要介绍了React 对state的理解,需要的朋友可以参考下
    2021-09-09
  • JavaScript中的useRef 和 useState介绍

    JavaScript中的useRef 和 useState介绍

    这篇文章主要给大家分享的是 JavaScript中的useRef 和 useState介绍,下列文章,我们将学习 useRef 和 useState hook是什么,它们的区别以及何时使用哪个。 这篇文章中的代码示例将仅涉及功能组件,但是大多数差异和用途涵盖了类和功能组件,需要的朋友可以参考一下
    2021-11-11
  • React forwardRef的使用方法及注意点

    React forwardRef的使用方法及注意点

    React.forwardRef的API中ref必须指向dom元素而不是React组件,通过一段示例代码给大家介绍了React forwardRef使用方法及注意点还有一些特殊情况分析,感兴趣的朋友跟随小编一起看看吧
    2021-06-06

最新评论