你真的了解react中的setState吗?(setState现象及原理全方位解析)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 在刚开始学习react的时候,我们会经常使用到setState改变状态,既然用的多,那么就应该思考:为什么要使用setState?setState是'异步'的吗?本篇文章就围绕着这两个问题展开

前言

在刚开始学习react的时候,我们会经常使用到setState改变状态,既然用的多,那么就应该思考:==为什么要使用setState?== ==setState是'异步'的吗?== 本篇文章就围绕着这两个问题展开

为什么要使用setState?

先来看一个简单的setState例子:
这是一个比较基础的例子,点击按钮改变state中msg的值

import React, { Component } from 'react'

export class App extends Component {
    state = {
        msg: 'hello world'
    }
    render() {
        return (
            <div>App
                <h2>{this.state.msg}</h2>
                <button onClick={this.change}>change</button>
            </div>
        )
    }
    // setState继承自Component
    change = () => {
        this.setState({msg: 'haha'})
    }
}

export default App

==那么我们为什么要使用setState?==
因为我们修改了状态state的时候,希望React根据最新的state来重新渲染界面,直接修改的方式,react并不会知道状态发生了改变。
react没有实现类似于Vue2中Object.defineProperty或者是Vue3 proxy的方式来监听数据的变化,必须通过setState来告知react状态的改变。
setState是继承自Component,当我们调用setState的时候,会重新执行render方法。

setState是'异步'的吗

对于这个问题,还是用以下不同情形的例子来进行解答:

例一:生命周期函数中使用

1.在componentDidMount函数中使用 this.setState赋值,并在它和componentDidUpdate函数中进行打印

import React, { Component } from 'react'

export class App extends Component {
    state = {
        count: 0
    }
    componentDidMount() {
        this.setState({count: 1})
        console.log(this.state.count) // 0
    }
    componentDidUpdate() {
        console.log(this.state.count) // 1
    }
    render() {
        return (
            <div></div>
        )
    }
    // setState继承自Component
    change = () => {
        this.setState({msg: 'haha'})
    }
}

export default App

查看结果,componentDidUpdate函数中打印0,componentDidUpdate函数打印1,这说明setState在生命周期是异步的

来看下一个例子

例二:在合成事件中使用

2.点击按钮触发change事件,事件中使用this.setState修改state中count的值,并打印this.state.count

import React, { Component } from 'react'
// 在合成事件里,setState是异步的
export class App extends Component {
    state = {
        count: 0
    }
    render() {
        return (
            <div>App
                <h2>{this.state.count}</h2>
                {/* 这个就是合成事件 */}
                <button onClick={this.change}>change</button>
            </div>
        )
    }
    // setState继承自Component
    change = () => {
        this.setState({count: 1})
        console.log(this.state.count) // 0
     
    }
}

export default App

运行查看结果
在这里插入图片描述
这里点击了按钮,上面数据已经更改为1了,但是控制台打印的却是9,这是为何呢?
==理论来讲执行代码的过程是同步的,从上往下。出现异步的结果是因为合成事件和生命周期中,调用顺序是在更新之前,所以导致我们没有办法立即拿到更新后的值所以才形成了所谓的异步现象。这里说的异步并不是指内部由异步代码实现的==

例三:在setTimeout中使用

3.写一个定时器的例子,在里面使用this.setState修改值并打印:

import React, { Component } from 'react'
export class App extends Component {
    state = {
        count: 0
    }
    componentDidMount() {
        setTimeout(() => {
            this.setState({count: 1})
            console.log(this.state.count) // 1
        }, 0)
    }
    render() {
        return (
            <div>App
                <h2>{this.state.count}</h2>
            </div>
        )
    }
}

export default App

查看结果发现打印的是1,说明setTimeout里setState是同步的

例四:在原生事件中使用

  1. 再来一个原生事件的例子,点击按钮触发click,更改数据并且打印:
import React, { Component } from 'react'
// 在原生事件中是同步的
export class App extends Component {
    state = {
        count: 0
    }
    componentDidMount() {
        document.querySelector('button').addEventListener(
            'click',
            (e) => {
                this.click()
            },
            false
        )
    }
    click() {
        this.setState({count: 1})
        console.log(this.state.count)  // 1
    }
    render() {
        return (
            <div>App
                <h2>{this.state.count}</h2>
                <button>按钮</button>
            </div>
        )
    }
}

export default App

最后的运行结果为1,说明在原生事件中是同步的

总结:

setState在生命周期和合成事件里面是异步的,在setTimeout和原生事件中是同步的

相关文章
|
4天前
|
域名解析 缓存 网络协议
DNS解析过程原理!
DNS解析过程原理!
|
11天前
|
前端开发 JavaScript 算法
如何学习react原理
【8月更文挑战第9天】 如何学习react原理
29 6
|
12天前
|
域名解析 负载均衡 网络协议
【域名解析DNS专栏】DNS解析中的Anycast技术:原理与优势
在互联网中,DNS将域名转换为IP地址至关重要。Anycast技术通过将同一IP地址分配给多台地理上分散的服务器,确保客户端总能连接到最近且最轻载的服务器,从而加速DNS解析、实现负载均衡、提升抵御DDoS攻击的能力及服务高可用性。通过动态路由协议如BGP实现,Anycast极大地增强了DNS系统的性能和稳定性。
35 2
|
1天前
|
域名解析 存储 缓存
域名服务器 (DNS):工作原理及其优势
【8月更文挑战第19天】
18 0
|
5天前
|
安全 Nacos 数据安全/隐私保护
【技术干货】破解Nacos安全隐患:连接用户名与密码明文传输!掌握HTTPS、JWT与OAuth2.0加密秘籍,打造坚不可摧的微服务注册与配置中心!从原理到实践,全方位解析如何构建安全防护体系,让您从此告别数据泄露风险!
【8月更文挑战第15天】Nacos是一款广受好评的微服务注册与配置中心,但其连接用户名和密码的明文传输成为安全隐患。本文探讨加密策略提升安全性。首先介绍明文传输风险,随后对比三种加密方案:HTTPS简化数据保护;JWT令牌减少凭证传输,适配分布式环境;OAuth2.0增强安全,支持多授权模式。每种方案各有千秋,开发者需根据具体需求选择最佳实践,确保服务安全稳定运行。
22 0
|
7天前
|
域名解析 缓存 负载均衡
深度解析Nginx正向代理的原理与实现
Nginx虽然主要被用作反向代理,但也可以通过一些特殊配置用作正向代理。虽然不是它的主流用途,但它仍能以其高性能和高稳定性为用户提供代理服务。不过,出于安全性和匿名性的考虑,在使用它作为正向代理时须谨慎配置,并根据实际需求做出调整。
22 0
|
8天前
ArrayBlockingQueue原理解析
该文章主要讲述了ArrayBlockingQueue的实现原理。
React-52:setState的两种更新状态的方式
React-52:setState的两种更新状态的方式
117 0
React-52:setState的两种更新状态的方式
|
3月前
|
设计模式 前端开发 数据可视化
【第4期】一文了解React UI 组件库
【第4期】一文了解React UI 组件库
266 0
|
3月前
|
资源调度 前端开发 JavaScript
React 的antd-mobile 组件库,嵌套路由
React 的antd-mobile 组件库,嵌套路由
91 0

推荐镜像

更多