一文带你掌握React类式组件中setState的应用

 更新时间:2024年02月29日 10:30:09   作者:进击的松鼠  
这篇文章主要为大家详细介绍了介绍了React类式组件中setState的三种写法以及简单讨论下setState 到底是同步的还是异步的,感兴趣的可以了解下

在 React 类式组件中,我们并不能直接通过修改 state 的值来让页面发生更新,而是必须通过 setState 的方式让 React 重新渲染页面,setState 来自于哪里呢?来自于继承 React 的 Component 类中,例如定义一个 App 类: class App extends Component ,在类中我们可以直接通过 this.setState 的方式来修改 state 的值,并让其调用 render 函数重新渲染页面。

setState 的三种写法

基本方式

import React, { Component } from 'react'

export class App extends Component {
  constructor(props) {
    super(props)
    
    this.state = {
      title: "React"
    }
  }
  
  changeText() {
    // 方式一:最基本的使用方式
    this.setState({
      title: "React类组件"
    })
  }
  
  render() {
    const { title } = this.state

    return (
      <div>
        <h1>title: {title}</h1>
        <button onClick={e => this.changeText()}>修改标题</button>
      </div>
    )
  }
}

setState 可以传入一个回调函数

作用:

  • 可以在回调函数中编写新的 state 的逻辑。
  • 当前的回调函数会将之前的 stateprops 传递进来。
import React, { Component } from 'react'

export class App extends Component {
  constructor(props) {
    super(props)
    
    this.state = {
      title: "React"
    }
  }
  
  changeText() {
    // 方式二:在setState中传入回调函数
    this.setState((state, props) => {
      // 可以获取之前的 state 和 props 值
      console.log(state.title, props)
      // 可以编写一些新的对state处理的逻辑
      return {
        title: state.title + "Native"
      }
    }
  }
  
  render() {
    const { title } = this.state
    
    return (
      <div>
        <h1>title: {title}</h1>
        <button onClick={e => this.changeText()}>修改标题</button>
      </div>
    )
  }
}

setState 在 React 的事件处理中是一个异步调用

我们并不能在执行完 setState 之后立马拿到最新的 state 的结果,可以在 setState 中传入第二个参数: callback 回调函数,用来获取数据更新之后(数据合并)的最新值。

import React, { Component } from 'react'

export class App extends Component {
  constructor(props) {
    super(props)
    
    this.state = {
      title: "React"
    }
  }
  
  changeText() {
    // 方式三:通过 setState 方法的第二个参数, 通过回调函数拿到更新后的值
    this.setState({ title: 'Redux' }, () => {
      console.log("在回调函数中获取更新后的值:", this.state.title) // Redux
    })
    console.log('因为异步获取的还是原来的值', this.state.title) // React
  }
  
  render() {
    const { title } = this.state
    
    return (
      <div>
        <h1>title: {title}</h1>
        <button onClick={e => this.changeText()}>修改标题</button>
      </div>
    )
  }
}

setState 的设计是异步的

React 中 setState 的设计为什么是异步的,针对这一讨论,Redux 的作者认为:setState 设计成异步,一方面可以显著提升性能,这是因为 React 每次调用 setState 都会进行一次更新,render 函数就会被频繁的调用,页面频繁的被渲染,为了解决这一问题,批量的进行更新是最得体的方法;另一方面可以使 stateprops 保持同步,因为存在一种情况,如果同步更新 state,这时还没有执行 render 函数,stateprops 不能保持同步。

export class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      count: 0
    }
  }

  increment() {
    this.setState({
      count: this.state.count + 1
    })
    this.setState({
      count: this.state.count + 1
    })
    this.setState({
      count: this.state.count + 1
    })
    console.log(this.state.count) // 1
  }

  render() {
    const { count } = this.state

    return (
      <div>
        <h1>{count}</h1>
        <button onClick={e => this.increment()}>count+1</button>
      </div>
    )
  }
}

点击增加按钮后 count 值变为 1,因为 setState 默认是一个异步的方法,默认会收集一段时间内所有的更新, 然后再统一更新 React。出于性能考虑,React 会把多个 setState() 调用合并成一个调用,所以点击按钮之后 count值 为 1,再次点击其结果会加 1 变为 2。

其原理就是通过 Object.assign() 方法对旧 state 和更改后的 state 进行一个合并。

要解决合并这个问题,可以让 setState() 接收一个函数而不是一个对象。

export class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      count: 0
    }
  }

  increment() {
    this.setState((state) => {
      return {
        count: state.count + 1
      }
    })
    this.setState((state) => {
      return {
        count: state.count + 1
      }
    })
    this.setState((state) => {
      return {
        count: state.count + 1
      }
    })
    console.log(this.state.count) // 3
  }

  render() {
    const { count } = this.state

    return (
      <div>
        <h1>{count}</h1>
        <button onClick={e => this.increment()}>count+1</button>
      </div>
    )
  }
}

点击增加按钮后 count 值变为 3,再次点击其结果会在基础上加 3 变为 6。

setState 到底是同步的还是异步的

React18 版本之前,在组件生命周期或 React 合成事件中,setState异步的;在 setTimeout 或者原生 dom 事件中,setState同步的

import React, { Component } from 'react'

export class App extends Component {
  constructor(props) {
    super(props)
    
    this.state = {
      title: "React"
    }
  }
  
  changeText() {
    setTimeout(() => {
      // 在react18之前, setTimeout中setState操作, 是同步操作
      this.setState({
        title: 'React学习笔记'
      })
      console.log(this.state.title) // ReactReact学习笔记
    }, 0)
  }
  
  render() {
    const { title } = this.state
    
    return (
      <div>
        <h1>title: {title}</h1>
        <button onClick={e => this.changeText()}>修改标题</button>
      </div>
    )
  }
}

React18版本之后,所有操作默认都是异步处理的

import React, { Component } from 'react'

export class App extends Component {
  constructor(props) {
    super(props)
    
    this.state = {
      title: "React"
    }
  }
  
  changeText() {
    setTimeout(() => {
      // 在react18之后, setTimeout中setState异步操作(批处理)
      this.setState({
        title: 'React学习笔记'
      })
      console.log(this.state.title) // React
    }, 0)
  }
  
  render() {
    const { title } = this.state
    
    return (
      <div>
        <h1>title: {title}</h1>
        <button onClick={e => this.changeText()}>修改标题</button>
      </div>
    )
  }
}

但是官方表示可以通过 flushSync 函数获取到同步的结果。

import React, { Component } from 'react'
import { flushSync } from 'react-dom'

export class App extends Component {
  constructor(props) {
    super(props)
    
    this.state = {
      title: "React"
    }
  }
  
  changeText() {
    setTimeout(() => {
      // 执行flushSync函数就可以拿到同步结果
      flushSync(() => {
        this.setState({ title: 'React学习笔记' })
      })
      console.log(this.state.title) // React学习笔记
    }, 0)
  }
  
  render() {
    const { title } = this.state
    
    return (
      <div>
        <h1>title: {title}</h1>
        <button onClick={e => this.changeText()}>修改标题</button>
      </div>
    )
  }
}

由此我们可以总结出 React 中的 setState 还是有很多奥秘的,其背后的设计思想是值得我们学习的,值的强调的是,React18 已经全面拥抱函数式组件,React Hooks 已经脱颖而出。

到此这篇关于一文带你掌握React类式组件中setState的应用的文章就介绍到这了,更多相关React类式组件setState内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React实现轮播效果

    React实现轮播效果

    这篇文章主要为大家详细介绍了React实现轮播效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • React性能优化系列之减少props改变的实现方法

    React性能优化系列之减少props改变的实现方法

    这篇文章主要介绍了React性能优化系列之减少props改变的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • React 中没有 v-model如何优雅地处理表单输入(最新推荐)

    React 中没有 v-model如何优雅地处理表单输入(最新推荐)

    本文介绍了React中没有v-model如何优雅地处理表单输入,主要讲解了基础受控组件和非受控组件两种实现方案,并深入解析了受控组件和非受控组件的概念,感兴趣的朋友跟随小编一起看看吧
    2026-02-02
  • React Native 中实现倒计时功能

    React Native 中实现倒计时功能

    这篇文章主要介绍了React Native中实现倒计时功能示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • React+JWT登录界面实现的完整流程

    React+JWT登录界面实现的完整流程

    React是一个用于渲染用户界面的JavaScript工具库,UI是由类似按钮、文本框以及图片之类的小零件构成的,这篇文章主要介绍了React+JWT登录界面实现的完整流程,需要的朋友可以参考下
    2026-04-04
  • 在 React Native 中给第三方库打补丁的过程解析

    在 React Native 中给第三方库打补丁的过程解析

    这篇文章主要介绍了在 React Native 中给第三方库打补丁的过程解析,有时使用了某个React Native 第三方库,可是它有些问题,我们不得不修改它的源码,本文介绍如何修改源码又不会意外丢失修改结果的方法,需要的朋友可以参考下
    2022-08-08
  • react中useState改变值不渲染的解决方式

    react中useState改变值不渲染的解决方式

    这篇文章主要介绍了react中useState改变值不渲染的解决方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • React中常用的一些钩子函数总结

    React中常用的一些钩子函数总结

    这篇文章给大家总结了React中常用的一些钩子函数,文中通过代码示例给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-01-01
  • 关于useEffect执行两次的问题及解决

    关于useEffect执行两次的问题及解决

    这篇文章主要介绍了关于useEffect执行两次的问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • useState 解决文本框无法输入的问题详解

    useState 解决文本框无法输入的问题详解

    这篇文章主要为大家介绍了useState 解决文本框无法输入的问题详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论