一、为什么要使用 setState 方法,如何用?

在 React 中,组件分为 有状态组件 和 无状态组件,有状态组件就是能够定义 state 的组件,比如类组件,无状态组件反之,比如函数组件。state 就是用来描述事物在某时刻的数据,可以被改变,改变后与视图相映射,用来保存数据和响应视图。

虽然状态可以改变,但不是响应式的,动态改变并没有与视图响应,想要改变并响应视图则需要 setState 修改并更新视图。

使用方法:this.setState({ 修改的数据 })

setState并不会影响其他没有进行修改的数据,此方法是从Component中继承过来的

import React, { Component } from 'react'
import ReactDOM from 'react-dom'export default class App extends Component {// 定义 statestate = {count: 0,list: [1, 2, 3],person: {name: 'jack',age: 18,},}changeCount = () => {// this.state.count++// 上面的写法并不能更新视图,想要双向更新只能利用 setState 方法this.setState({count: this.state.count,})}changeList = () => {// 同理this.state.list.push('Hello React')this.setState({list: this.state.list,})}changePerson = () => {this.state.person.name = 'ifer'this.state.person.age = 19this.setState({person: this.state.person,})}render() {return (<div><h3>count输出</h3><p>{this.state.count}</p><button onClick={this.changeCount}>click</button><hr /><h3>list输出</h3><ul>{this.state.list.map((item, index) => (<li key={index}>{item}</li>))}</ul><button onClick={this.changeList}>click</button><hr /><h3>person输出</h3><p>{this.state.person.name} {this.state.person.age}</p><button onClick={this.changePerson}>click</button></div>)}
}ReactDOM.render(<App />, document.querySelector('#root'))

状态有个特性是不可变性,就是不可以直接修改原数据,而是直接产生一个新的数据,通过 setState 方法把新的数据覆盖原有的数据,从而进行响应视图,这么做有利于性能优化和 SCU。

二、setState 使用触发的钩子函数

  1. render() ———— 每次组件渲染都会触发

    注意:render()中不要调用 setState 方法,会发生死循环。

  2. componentDidUpdate() ———— 组件更新(完成DOM渲染)后触发

三、setState 是同步代码

虽说 setState 很多人说是异步的,但是它本身的执行过程和代码是同步的,只是它在合并数据与钩子函数的调用顺序在更新后无法拿到值,形成了 异步 ,我们可以通过第二个参数拿到更新后的结果。

changeText() {this.setState({age: 20}, () => {console.log(this.state.age); // 文本已经被改变,得到的是20});
}

也可以通过钩子函数获取修改后的值

componentDidUpdate() {console.log(this.state.age);
}

什么时候“同步”,什么时候“异步”?

  • 一般情况下(常见在生命周期或者是合成事件处理函数中),通过 setState() 方法来更新状态,表现是 异步 的。

    state = { count: 1 }this.setState({count: this.state.count + 1,
    })console.log(this.state.count) // 1
    // 通过 DOM 不能立马获取更新后的值
  • 当执行到 setState 时,React 出于性能考虑,并不会立马执行修改 state ,而是先把当前更新对象以及后续的合并到一起,放在一个更新队列里进行合并操作,这期间并不会影响后续代码执行。且多次调用会合并,以最后一次渲染为主,以此来进行性能优化。
    this.setState({count: this.state.count + 1,
    })
    this.setState({count: this.state.count + 2,
    })
    this.setState({count: this.state.count + 3,
    })// 最后实现更新的是最后一个代码,前面的都会被覆盖

    如果想要实现一个一个实现,可以利用 setState 的第二个参数,第二个参数是一个回调函数,在更新完之后会执行

    // setState 有两个参数,第二个参数可以立即拿到更新后的值
    this.setState({}, () => {console.log('这个回调函数会在状态更新后立即执行')
    })
    this.setState(() => ({count: this.state.count + 1
    }))
    // prevStart 是最近一次的更新的数据
    this.setState((prevStart) => ({count: prevStart.count + 2
    }))
    this.setState((prevStart) => ({count: prevStart.count + 3
    }))

    上面确实可以累加,把累加的结果渲染到页面上,但依然不能改变异步更新的表现形式

  • 如果在 setTimeout/setInterval 或者原生事件(比如点击事件等)的回调中,或者是在 setState 前面遇到 await 后续表现都为 同步 的。

    利用定时器

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

    原生事件

    import React, { Component, createRef } from 'react'export default class App extends Component {state = {count: 1,}countRef = createRef()componentDidMount() {this.countRef.current.onclick = () => {this.setState({count: this.state.count + 1,})console.log(this.state.count) // 2}}render() {return (<div><h2>{this.state.count}</h2><button ref={this.countRef}>点击</button></div>)}
    }

    async写法

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

React中setState方法详解相关推荐

  1. js路由在php上面使用,React中路由使用详解

    这次给大家带来React中路由使用详解,React中路由使用的注意事项有哪些,下面就是实战案例,一起来看一下. 路由 通过 URL 映射到对应的功能实现,React 的路由使用要先引入 react-r ...

  2. numpy中reshape方法详解

    numpy中reshape方法详解_zhanggonglalala的博客-CSDN博客_reshape

  3. JavaScript中getBoundingClientRect()方法详解

    JavaScript中getBoundingClientRect()方法详解 getBoundingClientRect() 这个方法返回一个矩形对象,包含四个属性:left.top.right和bo ...

  4. Pandas中resample方法详解

    Pandas中resample方法详解 Pandas中的resample,重新采样,是对原样本重新处理的一个方法,是一个对常规时间序列数据重新采样和频率转换的便捷的方法.重新取样时间序列数据. 方便的 ...

  5. php中魔术方法详解

    〝 古人学问遗无力,少壮功夫老始成 〞php中魔术方法详解,在php中有一类方法,很奇怪常,那就是只要满足一定条件,就会自己执行,那就是php中的魔术方法,码字不易,出精品更难,没有特别幸运,那么请先 ...

  6. Js中apply方法详解说明

    Js apply 方法 详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了, ...

  7. python中new方法详解及_Python中new方法的详解

    new_ 方法是什么? __new__方法其实就是创建对象的方法 new()方法是在类准备将自身实例化时调用. 一个类可以有多个位置参数和多个命名参数,而在实例化开始之后,在调用 init()方法之前 ...

  8. React中使用Vditor详解(自定义图片)

    安装 npm install vditor -s 引用 导入依赖包 import Vditor from "vditor"; 导入样式 import "vditor/sr ...

  9. 浅谈嵌入式MCU软件开发之S32K1xx系列MCU启动过程及重映射代码到RAM中运行方法详解

    内容提要 注:本文摘自NXP工程师胡恩伟的微信公众号"汽车电子expert成长之路",大家感兴趣可以关注一下. 引言 1. S32K1xx系列MCU启动过程详解(startup_S ...

最新文章

  1. python无限循环条件循环_Python - 条件控制、循环语句 - 第十二天
  2. vue 之 nextTick 与$nextTick
  3. 一键解锁解题秘籍,从向作者提问开始
  4. 大数据量下的集合过滤—Bloom Filter
  5. 设计模式系列-建造者模式
  6. VTK:可视化之HideActor
  7. [一天一个小知识]instanceof
  8. CentOS7系统上Kubernetes集群搭建
  9. python tkinter 背景色改变不了_python - Tkinter背景颜色问题 - 堆栈内存溢出
  10. Android的setVisibility的三个参数
  11. python pow函数用法_Python代码中pow()函数具有哪些功能呢?
  12. Remove Duplicates from Sorted Array
  13. 荣耀6plus+android5.1,荣耀6Plus Emui3.1-Android5.1.1 Root教程
  14. win10访问服务器文件夹慢,win10系统访问共享文件夹速度特别慢的操作方法
  15. VMware虚拟机没有网络
  16. [数据挖掘笔记] KMeans豆瓣文本聚类
  17. 《管理长歌行》——青蛙与蜘蛛的对话
  18. 二项式定理与杨辉三角
  19. 《深入理解Android内核设计思想(第2版)(上下册)》之Android源码下载及编译...
  20. matplotlib 多子图图例显示

热门文章

  1. 字符串类型的数字比较大小
  2. C++ atomic
  3. matlab中两个符号矩阵相加,MATLAB矩阵分析及符号运算.ppt
  4. 判断大文件是否上传成功(一个大文件上传到ftp,判断是否上传完成)
  5. bresenham画线算法的最简洁实现
  6. android中edittext属性,Android中EditText的inputType属性的详解
  7. extern变量c语言,C语言外部变量extern
  8. devtool里的7种SourceMap模式
  9. 安装pandas库报错_python中安装pandas
  10. 用python函数画德国国旗代码_用Python的turtle模块画国旗