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

简介: 在刚开始学习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和原生事件中是同步的

相关文章
|
3月前
|
缓存 前端开发 JavaScript
React Hooks深度解析与最佳实践:提升函数组件能力的终极指南
🌟蒋星熠Jaxonic,前端探索者。专注React Hooks深度实践,从原理到实战,分享状态管理、性能优化与自定义Hook精髓。助力开发者掌握函数组件的无限可能,共赴技术星辰大海!
React Hooks深度解析与最佳实践:提升函数组件能力的终极指南
|
前端开发 JavaScript
React 步骤条组件 Stepper 深入解析与常见问题
步骤条组件是构建多步骤表单或流程时的有力工具,帮助用户了解进度并导航。本文介绍了在React中实现简单步骤条的方法,包括基本结构、状态管理、样式处理及常见问题解决策略,如状态管理库的使用、自定义Hook的提取和CSS Modules的应用,以确保组件的健壮性和可维护性。
299 17
|
前端开发 JavaScript
React Hooks 全面解析
【10月更文挑战第11天】React Hooks 是 React 16.8 引入的新特性,允许在函数组件中使用状态和其他 React 特性,简化了状态管理和生命周期管理。本文从基础概念入手,详细介绍了 `useState` 和 `useEffect` 的用法,探讨了常见问题和易错点,并提供了代码示例。通过学习本文,你将更好地理解和使用 Hooks,提升开发效率。
259 4
|
10月前
|
前端开发
React 中高阶组件的原理是什么?
React 中高阶组件的原理是什么?
250 57
|
10月前
|
Web App开发 移动开发 前端开发
React音频播放器样式自定义全解析:从入门到避坑指南
在React中使用HTML5原生&lt;audio&gt;标签时,开发者常面临视觉一致性缺失、样式定制局限和交互体验割裂等问题。通过隐藏原生控件并构建自定义UI层,可以实现完全可控的播放器视觉风格,避免状态不同步等典型问题。结合事件监听、进度条拖拽、浏览器兼容性处理及性能优化技巧,可构建高性能、可维护的音频组件,满足跨平台需求。建议优先使用成熟音频库(如react-player),仅在深度定制需求时采用原生方案。
432 12
|
11月前
|
Web App开发 监控 前端开发
React音频播放控制组件开发深度解析
本文介绍了构建React音频控制组件时遇到的关键问题及优化方案。主要包括: 1. **状态同步难题**:解决播放按钮与音频状态不同步的问题,通过双向绑定机制确保一致。 2. **跨浏览器兼容性**:处理Safari和Chrome预加载策略差异,确保`duration`属性正确获取。 3. **进度控制优化**:避免使用`setInterval`,采用`requestAnimationFrame`提升性能;优化拖拽交互,防止音频卡顿。 4. **音量控制进阶**:实现渐变音量调节和静音状态同步。
471 15
|
前端开发 UED
React 文本区域组件 Textarea:深入解析与优化
本文介绍了 React 中 Textarea 组件的基础用法、常见问题及优化方法,包括状态绑定、初始值设置、样式自定义、性能优化和跨浏览器兼容性处理,并提供了代码案例。
410 9
|
前端开发 JavaScript
React Hooks 深入解析
React Hooks 深入解析
185 0
|
8月前
|
缓存 前端开发 数据安全/隐私保护
如何使用组合组件和高阶组件实现复杂的 React 应用程序?
如何使用组合组件和高阶组件实现复杂的 React 应用程序?
301 68
|
8月前
|
缓存 前端开发 Java
在 React 中,组合组件和高阶组件在性能方面有何区别?
在 React 中,组合组件和高阶组件在性能方面有何区别?
276 67

推荐镜像

更多
  • DNS