一、是什么

一个组件的显示形态可以由数据状态和外部参数所决定,而数据状态就是state

当需要修改里面的值的状态需要通过调用setState来改变,从而达到更新组件内部数据的作用

如下例子:

import React, { Component } from 'react'

export default class App extends Component {
constructor(props) {
super(props); this.state = {
message: "Hello World"
}
} render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={e => this.changeText()}>面试官系列</button>
</div>
)
} changeText() {
this.setState({
message: "JS每日一题"
})
}
}

通过点击按钮触发onclick事件,执行this.setState方法更新state状态,然后重新执行render函数,从而导致页面的视图更新

如果直接修改state的状态,如下:

changeText() {
this.state.message = "JS每日一题";
}

我们会发现页面并不会有任何反应,但是state的状态是已经发生了改变

这是因为React并不像vue2中调用Object.defineProperty数据响应式或者Vue3调用Proxy监听数据的变化

必须通过setState方法来告知react组件state已经发生了改变

关于state方法的定义是从React.Component中继承,定义的源码如下:

Component.prototype.setState = function(partialState, callback) {
invariant(
typeof partialState === 'object' ||
typeof partialState === 'function' ||
partialState == null,
'setState(...): takes an object of state variables to update or a ' +
'function which returns an object of state variables.',
);
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

从上面可以看到setState第一个参数可以是一个对象,或者是一个函数,而第二个参数是一个回调函数,用于可以实时的获取到更新之后的数据

二、更新类型

在使用setState更新数据的时候,setState的更新类型分成:

  • 异步更新
  • 同步更新

异步更新

先举出一个例子:

changeText() {
this.setState({
message: "你好啊"
})
console.log(this.state.message); // Hello World
}

从上面可以看到,最终打印结果为Hello world,并不能在执行完setState之后立马拿到最新的state的结果

如果想要立刻获取更新后的值,在第二个参数的回调中更新后会执行

changeText() {
this.setState({
message: "你好啊"
}, () => {
console.log(this.state.message); // 你好啊
});
}

同步更新

同样先给出一个在setTimeout中更新的例子:

changeText() {
setTimeout(() => {
this.setState({
message: "你好啊
});
console.log(this.state.message); // 你好啊
}, 0);
}

上面的例子中,可以看到更新是同步

再来举一个原生DOM事件的例子:

componentDidMount() {
const btnEl = document.getElementById("btn");
btnEl.addEventListener('click', () => {
this.setState({
message: "你好啊"
});
console.log(this.state.message); // 你好啊
})
}

小结

  • 在组件生命周期或React合成事件中,setState是异步
  • 在setTimeout或者原生dom事件中,setState是同步

三、批量更新

同样先给出一个例子:

handleClick = () => {
this.setState({
count: this.state.count + 1,
})
console.log(this.state.count) // 1 this.setState({
count: this.state.count + 1,
})
console.log(this.state.count) // 1 this.setState({
count: this.state.count + 1,
})
console.log(this.state.count) // 1
}

点击按钮触发事件,打印的都是 1,页面显示 count 的值为 2

对同一个值进行多次 setState, setState 的批量更新策略会对其进行覆盖,取最后一次的执行结果

上述的例子,实际等价于如下:

Object.assign(
previousState,
{index: state.count+ 1},
{index: state.count+ 1},
...
)

由于后面的数据会覆盖前面的更改,所以最终只加了一次

如果是下一个state依赖前一个state的话,推荐给setState一个参数传入一个function,如下:

onClick = () => {
this.setState((prevState, props) => {
return {count: prevState.count + 1};
});
this.setState((prevState, props) => {
return {count: prevState.count + 1};
});
}

而在setTimeout或者原生dom事件中,由于是同步的操作,所以并不会进行覆盖现象

React中的setState执行机制的更多相关文章

  1. React的setState执行机制

    1. setState基本特点 1. setState是同步执行的 setState是同步执行的,但是state并不一定会同步更新 2. setState在React生命周期和合成事件中批量覆盖执行 ...

  2. react中的setState的使用和深入理解

    前端框架从MVC过渡到MVVM.从DOM操作到数据驱动,一直在不断的进步着,提升着, angular中用的是watcher对象,vue是观察者模式,react就是state了,他们各有各的特点,没有好 ...

  3. react中this.setState的理解

    this.setState作用? 在react中要修改this.state要使用this.setState,因为this.state只是一个对象,单纯的修改state并不会触发ui更新.所以我们需要用 ...

  4. react 中 EventEmitter 事件总线机制

    此机制可用于 react 中兄弟组件中的通信 npm install events -S 事件总线: // eventBus.js import {EventEmitter} from 'events ...

  5. React中的setState到底发生了什么?

    https://yq.aliyun.com/ziliao/301671 https://segmentfault.com/a/1190000014498196 https://blog.csdn.ne ...

  6. 3.React中的setstate的几个现象

    转载segfault 上面的一篇文章,https://segmentfault.com/a/1190000014498196 1.在同一个方法中多次setState是会被合并的,并且对相同属性的设置只 ...

  7. react 中的 setState

    语法:setState(newState [,callback]) 1.只要有入门基础的同学都知道 setState({...}) 是更新组件中的 state 内容 2.但是,setState 是异步 ...

  8. React中this.setState是同步还是异步?为什么要设计成异步?

    在使用react的时候,this.setState为什么是异步呢? 一直以来没有深思这个问题.昨天就此问题搜索了一下. react创始人之一 Dan Abramovgaearon在GitHub上回答了 ...

  9. React中的setState(obj)

    1.setState(obj)  只能浅merge obj,对于复杂对象结构的不行 比如:  this.state = {   data:{  idx:1 }   }   this.setState( ...

  10. 从源码的角度再看 React JS 中的 setState

    在这一篇文章中,我们从源码的角度再次理解下 setState 的更新机制,供深入研究学习之用. 在上一篇手记「深入理解 React JS 中的 setState」中,我们简单地理解了 React 中 ...

随机推荐

  1. Openssl命令详解 - 证书篇

    生成自签证书 # 设置CA证书subject CA_SUBJ="/C=CN/ST=ShanDong/L=JiNan/O=sec/OU=sec/CN=www.hxy.com/emailAddr ...

  2. 开源:基于mybatis和jpa的数据库安全加密脱敏插件,围观交流

    开源:基于mybatis和jpa的数据库安全加密脱敏插件,围观交流

  3. git拉项目, 1.新建目录 2 git clone 地址 . (重点最后的点)

  4. ohmyposh 安装 - 基于 powershell7.2.1 - 最后改成 profile自定义

    今天偶然下载了 powershell7.2.1 https://mydown.yesky.com/pcsoft/468254.html 这想着 vscode也支持了,得装一个 ohmyposh的主题啊 ...

  5. SQL之QL

    从中文语法上来说,应该先写FROM语句比较好理解 基础查询语句 SELECT [DISTINCT] target-list FROM tables WHERE qualification GROUP ...

  6. 【个人笔记】Nestjs使用TypeORM注意点

    在Nestjs使用TypeORM还是有一些注意点. entities路径配置注意点 在nestjs中使用TypeORM,需要配置数据库连接(以MySQL为例).需要特别注意的是配置参数里面的entit ...

  7. 09.Java数据算法

    好消息 博客笔记大汇总[15年10月到至今],包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期 ...

  8. Python简单程序设计(Unicode编码与字符间转换篇)

    如题: (误以为本题存在两者之间互相转换,后附上逆过程代码) 解题方式如下: 逆过程:

  9. python批量发邮箱

    1.首先登录邮箱中开启服务 2.获取到授权码后复制下来,放入如下含授权码的引号中: 1 smtp_obj.login("**********@qq.com", "授权码& ...

  10. mysql where子句 区分 大小写

    解决办法 使用binary关键字,此时就能区分大小写了 SELECT * FROM `tb_test` WHERE BINARY COL_1='abc'