react中setState方法到底是异步还是同步,其实这个是分在什么条件下是异步或者同步。

1.先来回顾一下react组件中改变state的几种方式:

import React, { Component } from 'react'

class Index extends Component {
state={
count:1
}
test1 = () => {
// 通过回调函数的形式
this.setState((state,props)=>({
count:state.count+1
}));
console.log('test1 setState()之后',this.state.count);
}
test2 = () => {
// 通过对象的方式(注意:此方法多次设置会合并且只调用一次!)
this.setState({
count:this.state.count+1
});
console.log('test2 setState()之后',this.state.count);
}
test3 = () => {
// 不能直接修改state的值,此方法强烈不建议!!!因为不会触发重新render
this.state.count += 1;
}
test4 = () => {
// 在第二个callback拿到更新后的state
this.setState({
count:this.state.count+1
},()=>{// 在状态更新且页面更新(render)后执行
console.log('test4 setState()之后',this.state.count);
});
}
render() {
console.log('render');
return (
<div>
<h1>currentState:{this.state.count}</h1>
<button onClick={this.test1}>测试1</button>
<button onClick={this.test2}>测试2</button>
<button onClick={this.test3} style={{color:'red'}}>测试3</button>
<button onClick={this.test4}>测试4</button>
</div>
)
}
}
export default Index;

2.setState()更新状态是异步还是同步:

需要判断执行setState的位置

同步:在react控制的回调函数中:生命周期钩子/react事件监听回调

import React, { Component } from 'react'

class Index extends Component {
state={
count:1
}
/*
react事件监听回调中,setState()是异步状态
*/
update1 = () => {
console.log('update1 setState()之前',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('update1 setState()之后',this.state.count);
}
/*
react生命周期钩子中,setState()是异步更新状态
*/
componentDidMount() {
console.log('componentDidMount setState()之前',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('componentDidMount setState()之后',this.state.count);
} render() {
console.log('render');
return (
<div>
<h1>currentState:{this.state.count}</h1>
<button onClick={this.update1}>测试1</button>
<button onClick={this.update2}>测试2</button>
</div>
)
}
}
export default Index;

异步:非react控制的异步回调函数中:定时器回调/原生事件监听回调/Promise

import React, { Component } from 'react'

class Index extends Component {
state={
count:1
}
/*
定时器回调
*/
update1 = () => {
setTimeout(()=>{
console.log('setTimeout setState()之前',this.state.count);//
this.setState((state,props)=>({
count:state.count+1
}));
console.log('setTimeout setState()之后',this.state.count);//
});
}
/*
原生事件回调
*/
update2 = () => {
const h1 = this.refs.count;
h1.onclick = () => {
console.log('onClick setState()之前',this.state.count);//
this.setState((state,props)=>({
count:state.count+1
}));
console.log('onClick setState()之后',this.state.count);//
}
}
/*
Promise回调
*/
update3 = () => {
Promise.resolve().then(value=>{
console.log('Promise setState()之前',this.state.count);//
this.setState((state,props)=>({
count:state.count+1
}));
console.log('Promise setState()之后',this.state.count);//
});
} render() {
console.log('render');
return (
<div>
<h1 ref='count'>currentState:{this.state.count}</h1>
<button onClick={this.update1}>测试1</button>
<button onClick={this.update2}>测试2</button>
<button onClick={this.update3}>测试3</button>
</div>
)
}
}
export default Index;

3.setState()多次调用的问题:

异步的setState()

(1)多次调用,处理方法:

setState({}):合并更新一次状态,只调用一次render()更新界面,多次调用会合并为一个,后面的值会覆盖前面的值。

setState(fn):更新多次状态,只调用一次render()更新界面,多次调用不会合并为一个,后面的值会覆盖前面的值。

import React, { Component } from 'react'

class Index extends Component {
state={
count:1
}
update1 = () => {
console.log('update1 setState()之前',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('update1 setState()之后',this.state.count);
console.log('update1 setState()之前2',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('update1 setState()之后2',this.state.count);
}
update2 = () => {
console.log('update2 setState()之前',this.state.count);
this.setState({
count:this.state.count+1
});
console.log('update2 setState()之后',this.state.count);
console.log('update2 setState()之前2',this.state.count);
this.setState({
count:this.state.count+1
});
console.log('update2 setState()之后2',this.state.count);
}
update3 = () => {
console.log('update3 setState()之前',this.state.count);
this.setState({
count:this.state.count+1
});
console.log('update3 setState()之后',this.state.count);
console.log('update3 setState()之前2',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));// 这里需要注意setState传参为函数模式时,state会确保拿到的是最新的值
console.log('update3 setState()之后2',this.state.count);
}
update4 = () => {
console.log('update4 setState()之前',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('update4 setState()之后',this.state.count);
console.log('update4 setState()之前2',this.state.count);
this.setState({
count:this.state.count+1
});// 这里需要注意的是如果setState传参为对象且在最后,那么会与之前的setState合并
console.log('update4 setState()之后2',this.state.count);
}
render() {
console.log('render');
return (
<div>
<h1>currentState:{this.state.count}</h1>
<button onClick={this.update1}>测试1</button>
<button onClick={this.update2}>测试2</button>
<button onClick={this.update3}>测试3</button>
<button onClick={this.update4}>测试4</button>
</div>
)
}
}
export default Index;

(2)如何得到setState异步更新后的状态数据:

在setState()的callback回调函数中

4.react中常见的setState面试题(setState执行顺序)

import React, { Component } from 'react'
// setState执行顺序
class Index extends Component {
state={
count:0
}
componentDidMount() {
this.setState({count:this.state.count+1});
this.setState({count:this.state.count+1});
console.log(this.state.count);// 2 => 0
this.setState(state=>({count:state.count+1}));
this.setState(state=>({count:state.count+1}));
console.log(this.state.count);// 3 => 0
setTimeout(() => {
this.setState({count:this.state.count+1});
console.log('setTimeout',this.state.count);// 10 => 6
this.setState({count:this.state.count+1});
console.log('setTimeout',this.state.count);// 12 => 7
});
Promise.resolve().then(value=>{
this.setState({count:this.state.count+1});
console.log('Promise',this.state.count);// 6 => 4
this.setState({count:this.state.count+1});
console.log('Promise',this.state.count);// 8 => 5
});
}
render() {
console.log('render',this.state.count);// 1 => 0 // 4 => 3 // 5 => 4 // 7 => 5 // 9 => 6 // 11 => 7
return (
<div>
<h1>currentState:{this.state.count}</h1>
<button onClick={this.update1}>测试1</button>
<button onClick={this.update2}>测试2</button>
<button onClick={this.update3}>测试3</button>
<button onClick={this.update4}>测试4</button>
</div>
)
}
}
export default Index;

总结:react中setState()更新状态的2种写法

1)setState(updater,[callback])

updater:为返回stateChange对象的函数:(state,props)=>stateChange,接收的state和props都保证为最新

2)setState(stateChange,[callback])

stateChange为对象,callback是可选的回调函数,在状态更新且界面更新后才执行

注意:

对象是函数方式的简写方式

如果新状态不依赖于原状态,则使用对象方式;

如果新状态依赖于原状态,则使用函数方式;

如果需要在setState()后获取最新的状态数据,在第二个callback函数中获取

React中setState学习总结的更多相关文章

  1. React的setState学习及应用

    React的setState学习及应用 一:作用: setState() 将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件.这是用于更新 ...

  2. React中setState同步更新策略

    setState 同步更新 我们在上文中提及,为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于this.state来计算 ...

  3. React中setState如何修改深层对象?

    在React中经常会使用到setState,因为在react生态中,state就是一切.在开发过程中,时长会在state中遇到一些比较复杂的数据结构,类似下面这样的: 这时需要我们修改list中obj ...

  4. React中setState的怪异行为 ——setState没有即时生效

    setState可以说是React中使用频率最高的一个函数了,我们都知道,React是通过管理状态来实现对组件的管理的,当this.setState()被调用的时候,React会重新调用render方 ...

  5. React中setState 什么时候是同步的,什么时候是异步的?

    class Example extends React.Component { constructor() { super(); this.state = { val: 0 }; } componen ...

  6. react中setState用法

    setState()更新状态的2种写法 setState(updater, [callback]), updater为返回stateChange对象的函数: (state, props) => ...

  7. React中setState注意事项

    setState是一个异步函数,异步获取数据 学习react在使用ref和setState操作DOM时会遇到的问题: ref获取ul结点元素 错误写法:得到的ul长度总是上一次输入后的长度 结果: 正 ...

  8. React中setState方法说明

    setState跟新数据是同步还是异步? setState跟新数据是异步的. 如何用代码表现出来是异步的. 点击按钮更新数据,然后去打印这个值看一下 setState跟新数据是异步的 class Fa ...

  9. 「React Native笔记」在React的 setState 中操作数组和对象的多种方法(合集)

    运用在React 中 setState的对象.数组的操作时是不能用类似array.push()等方法,因为push没有返回值,setState后会出现state变成Number,为了方便他人和自己查看 ...

随机推荐

  1. J.U.C剖析与解读1(Lock的实现)

    J.U.C剖析与解读1(Lock的实现) 前言 为了节省各位的时间,我简单介绍一下这篇文章.这篇文章主要分为三块:Lock的实现,AQS的由来(通过演变的方式),JUC三大工具类的使用与原理剖析. L ...

  2. 跑健壮性Monkey,出现一次Crash全过程-日志分析-Dotest董浩

    最近带着学生做的某个项目,跑健壮性Monkey,出现一次Crash全过程-日志分析: 准备:搭建adb环境.安装实际测试包:开始: Monkey命令: adb shell monkey -p com. ...

  3. vue学习笔记(九)vue-cli中的组件通信

    前言 在上一篇博客vue学习笔记(八)组件校验&通信中,我们学会了vue中组件的校验和父组件向子组件传递信息以及子组件通知父组件(父子组件通信),上一篇博客也提到那是对组件内容的刚刚开始,而本 ...

  4. Unicode和Ascii的区别

    计算机只能处理数字,如果要处理文本,就必须把文本转换成数字.    最早的计算机设计采用8bit作为一个字节,所以,一个字节只能表示的最大整数255.   0-255被用来表示数字和一些符号,这个编码 ...

  5. 转载-FileZilla Server源码分析(1)

    FileZilla Server源码分析(1) 分类: VC 2012-03-27 17:32 2363人阅读 评论(0) 收藏 举报 serversocketftp服务器usersockets工作 ...

  6. Maven安装目录分析

    maven目录结构介绍 bin: 包含了mvn运行的脚本(既在cmd输入命令执行依赖,在命令行输入任何一条mvn命令时,实际上就是在调用这些脚本) boot: 该目录只包含一个文件,是一个类加载器,m ...

  7. 侠梦说pinpoint--左侧服务地图调用量和WasOn过滤

    前言 这篇文章主要是从pinpoint-web界面入手,我们的目标是弄清楚两个问题: 1. pinpoint左侧服务地图上的调用量数据是怎么查询的? 2.界面查询条件WasOnly是什么意思? 左侧服 ...

  8. javaScript中的indexOf使用方法

    JavaScript中的indexOf使用方法 概述 indexOf大小写敏感,其中的O要大写 对于字符串而言 indexOf返回字符串第一次出现的位置,若没有出现返回-1 1 var str = & ...

  9. 高并发编程-AQS深入解析

    要点解说 AbstractQueuedSynchronizer简称AQS,它是java.util.concurrent包下CountDownLatch/FutureTask/ReentrantLock ...

  10. MVC WebApi 返回字符串

    [HttpGet] public HttpResponseMessage GetWebConfigValue(string key) { var response = Request.CreateRe ...