理解React中的setState函数

​在react的类组件中,修改state的状态,是通过setState这函数来进行修改的。

错误的写法:

import React, { Component } from 'react'

export default class UnderStandSetState extends Component {
    constructor() {
        super()
        this.state = {
            message: 'james'
        }
        this.changeMessage = this.changeMessage.bind(this)
    }

    changeMessage() {
        this.state.message = 'kobe'   
        console.log(this.state.message);    //kobe
    }

    render() {
        return (
            <div>
                <h1>{this.state.message}</h1>
                <button onClick={this.changeMessage}>改变文本</button>
            </div>
        )
    }
}

原因: 这样的写法,state的值虽然已经发生改变,但是react底层不知道state的值变了,所以页面上就不会更新。(这里跟vue的不一样,vue2有Object.defineProperty,vue3 的proxy对数据进行注册,监听)

正确的写法:

 changeMessage() {
    this.setState({    
        message: 'kobe'
    })
 }

通过setState函数来改变state的状态,页面上也会更新。

那么也会好奇?setState这个函数来自于哪里?

原因: class组件继承与react中的component,在component的原型上就有setState这个方法。

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的对象形式

 changeMessage() {
    this.setState({    
        message: 'kobe'
    }, () => {
        console.log(this.state.message)   //kobe(最新的值)
    })
 }

注意点:

this.state = {
    count: 1
}

btnAdd() {
    this.setState({
            count: this.state.count + 1
        })
        this.setState({
            count: this.state.count + 1
        })
        this.setState({
            count: this.state.count + 1
        })
}

render() {
    return (
    	<h1>{this.state.count}</h1>
        <button onClick={this.btnAdd}> + </button>
    )
}

当点击+的时候,看逻辑来说的话,应该会在原来的基础上+3。但是呢?并没有。这里他会进行合并,如果是相同的key值的话。类似于Javascript中的Object.assign()的工作原理。

setState的函数形式

 changeMessage() {
    this.setState((prevState, props) => {
        return {
            message: 'kobe'
        }
    }, () => {
        console.log(this.state.message)   //kobe(最新的值)
    })
 }

//参数1: 当前的state的状态
//参数2: 传递过来的props

注意点:

btnAdd() {
    this.setState((prev) => {
        return {
            count: prev.count + 1
        }
    })
    this.setState((prev) => {
        return {
            count: prev.count + 1
        }
    })
    this.setState((prev) => {
        return {
            count: prev.count + 1
        }
    })
}

这里就会跟我想的一样的执行,从1变为4

setState的函数形式,更加适用于处理复杂的逻辑处理。

setState函数同步?异步?

在使用setState的函数中,我们改变了值,下一步取值的话,往往是最开始的值,而不是最新的值(当然我们可以在setState的第二个参数拿到最新的值),造成这种原因是为什么呢?

setState通过一个队列机制实现state的更新。当执行setState时,会把需要更新的state合并后放入状态队列,而不会立刻更新this.state,利用这个队列机制可以高效的批量的更新state。

这样更加有利于性能优化。

一般情况下,在没有进行特殊处理下,setState是异步函数。

但是在一些情况下,它又是同步函数

情况一

在定时器中,是同步函数

changeMessage() {
    setTimeout(() => {
        this.setState({
            message: 'kobe'
        })
        console.log(this.state.message)   //kobe
    })
}

情况二:

在一些原生JS的API中,也是同步函数

btn.addEventListener('click', () => {
    this.setState({
            message: 'kobe'
        })
        console.log(this.state.message)   //kobe
    })
})

总结:

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

参考博客

https://www.cnblogs.com/katydids/p/10014111.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值