React学习笔记15-setState同步异步问题
先说结论:
setState处在同步的逻辑中会异步更新状态,更新真实dom。
连续调用 setState 不会连续进行虚拟dom的对比和页面的更新
setState处在异步的逻辑中,同步更新状态,更新真实dom。
1.同步状态
先看同步状态
/* eslint-disable react/no-direct-mutation-state */ import React, { Component } from 'react' export default class App extends Component { state = { count: 1 } render() { return ( <div> <div>{this.state.count}</div> <button onClick={ () => {
this.setState({
count: this.state.count + 1
})
console.log(this.state.count)
this.setState({
count: this.state.count + 1
})
console.log(this.state.count)
this.setState({
count: this.state.count + 1
})
} }>add1</button> </div> ) } }
可以看出来三个打印都是1,说明setState在同步环境下是异步进行更新的
并且执行了三次setState实际上只更新了一次dom
这是因为
react会根据是同步队列还是异步队列来指定一个来决定setState是否合并处理的标志位,
同步队列为true,
这时setState会异步执行,进行合并处理,
因为跟新的都是同一个状态所以会
合并为 this.setState({
count: this.state.count + 1
})
连续调用只会更新一次dom
2.同步状态下,如何获取dom更新后的state
/* eslint-disable react/no-direct-mutation-state */ import React, { Component } from 'react' export default class App extends Component { state = { count: 1 } render() { return ( <div> <div>{this.state.count}</div> <button onClick={ () => { // this.setState的第二个参数是一个函数, //可以看做状态更新和dom后的回调 this.setState({ count: this.state.count + 1 }, () => { console.log(this.state.count) }) this.setState({ count: this.state.count + 1 }, () => { console.log(this.state.count) }) this.setState({ count: this.state.count + 3 }, () => { console.log(this.state.count) }) /* 同步逻辑下,在setState的回调中可以打印出更新后的状态。这里因为是 合并处理,所以以最后一个为准,打印出来是1+3 = 4 */ } }>add1</button> </div> ) } }
如果在同步情况下想要获取dom更新后的state可以通过setState的第二个参数来获取
this.setState的第二个参数是一个函数,可以看做状态更新和dom后的回调
同步逻辑下,在setState的回调中可以打印出更新后的状态。这里因为是
合并处理,所以以最后一个为准,打印出来是1+3 = 4
3.异步状态
/* eslint-disable react/no-direct-mutation-state */ import React, { Component } from 'react' export default class App extends Component { state = { count: 1 } render() { return ( <div> <div>{this.state.count}</div> <button onClick={ () => { setTimeout(() => { //异步逻辑 this.setState({ count: this.state.count + 1 }) console.log(this.state.count) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) }, 0); } }>add</button> </div> ) } }
可以看到在异步状态下setState是同步调用的每次更新状态都会被打印下来,并且同步会更新状态和dom