一文讲清楚React中setState的使用方法和机制

一文讲清楚React中setState的使用方法和机制

1. setState是什么

import React from 'react'
class App extends React.Component{
    constructor(props){
        super(props)
        this.state={
            name:'tom'
        }
    }
    handleClick=()=>{
        this.setState({
            name:'new tom'
        })
    }
    render(){
        return(
            <div>
                <div>{this.state.name}</div>
                <button onClick={this.handleClick}>change name in by setState</button>
            </div>
        )
    }
}
export default App
  • 运行显示tom,点击按钮通过setState方法把name改为new tom,发现页面显示成了new tom

2. setState方法详解

2.1 setState参数详解

  • setState由两个参数,updater和callback,updater可以是对象也可以是函数
  • 我们下一个计数器的demo
import React from 'react'
class App extends React.Component{
    constructor(props){
        super(props)
        this.state={
            count:0
        }
    }
    handleClick=()=>{
        this.setState(preState=>({count:preState.count+1}))
    }
    render(){
        return(
            <div>
                <div>{this.state.count}</div>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
}
export default App
  • 点击+1,也能实现状态的改变并现实出来
  • 那么对象参数和函数参数有什么区别呢,先给出答案,如果是参数是对象,会进行事件合并,如果参数是函数,不会发生事件合并,上代码
  • 我们设置两个计数器,一个从参数对象更新,一个用参数函数更新,每点击一次按钮,计数器做三次+1操作
import React from 'react'
class App extends React.Component{
    constructor(props){
        super(props)
        this.state={
            count1:0,
            count2:0,
        }
    }
    handleClick=()=>{
        //第一个计数器用对象参数执行三次+1
        this.setState({
            count1:this.count1+1
        })
         this.setState({
            count1:this.count1+1
        })
         this.setState({
            count1:this.count1+1
        })
        //第2个计数器用函数参数执行三次+1
        this.setState(preState=>({count2:preState.count2+1}))
        this.setState(preState=>({count2:preState.count2+1}))
        this.setState(preState=>({count2:preState.count2+1}))
    }
    render(){
        return(
            <div>
                <div>count1:{this.state.count1}</div>
                <div>count2:{this.state.count2}</div>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
}
export default App
  • 运行
    在这里插入图片描述

  • 初始值都是0没问题

  • 然后点按钮
    在这里插入图片描述

  • 会发现count1只+1,而count2+3,这是因为setState在参数为对象的模式下,对批量操作会进行覆盖,只取最后一次结果执行

  • setState还有第二个参数,callback,我们在下面讲

2.2 setState同步异步问题

2.2.1 setState异步更新

  • 先直接上代码
import React from 'react'
class App extends React.Component{
    constructor(props){
        super(props)
        this.state={
            count:0
        }
    }
    handleClick=()=>{
        this.setState(preState=>({count:preState.count+1}))
        console.log(this.state.count)
    }
    render(){
        return(
            <div>
                <div>{this.state.count}</div>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
}
export default App
  • 运行,处置为.,然后点击+1按钮,发现页面显示1,但是console.log打印0
    在这里插入图片描述

  • 这是为什么呢,这是因为React在合成事件中,state是异步更新的

  • 为什么会是一步的呢,问题就出现在合成事件上,不懂合成事件的看这篇文章一文讲清楚React合成事件机制和this的绑定问题

  • 因为合成事件的原因,console.log的执行时机别state更新的时机要早,所以造成了异步现象

  • 同理,在生命周期函数中改变状态也会造成异步更新

  • 如果想要拿到更新后的state,就需要setState第二个参数callback,他会在UI更新后被调用

  • 我们这么改一下代码

import React from 'react'
class App extends React.Component{
    constructor(props){
        super(props)
        this.state={
            count:0
        }
    }
    handleClick=()=>{
        this.setState(preState=>({count:preState.count+1}),()=>{
            console.log(this.state.count)
        })
       
    }
    render(){
        return(
            <div>
                <div>{this.state.count}</div>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
}
export default App
  • 这时候我们拿到了同步的值
    在这里插入图片描述

2.2.2 setState同步更新

  • 上面说因合成事件会导致异步更新,那如果我们使用原生事件呢,上代码
import React from 'react'
class App extends React.Component{
    constructor(props){
        super(props)
        this.state={
            count:0
        }
    }
    componentDidMount(){
        document.getElementById('update').addEventListener('click',this.handleClick)
    }
    handleClick=()=>{
        this.setState(preState=>({count:preState.count+1}))
        console.log(this.state.count)
       
    }
    render(){
        return(
            <div>
                <div>{this.state.count}</div>
                <button id="update">+1</button>
            </div>
        )
    }
}
export default App
  • 运行会发现,还是打印0,哈哈哈,那是因为React在V16版本前,在原生事件和setTimeout中setState是同步事件,这里本来想演示这个来着,但是奈何坐着的React的版本比较高,这里建议大家切换低版本自己运行一下,代码肯定是没有任何问题的
  • React为了让setState在所有场景下保持一致性,从V16+开始,无论是合成事件、原生事件还是setTimeout都是保持异步,要获取更新后的状态请统一使用setState第二个回调函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

许先森森

爱我就打我

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值