最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • setState 详解

    正文概述 掘金(Jimmy_kiwi)   2021-08-03   538

    setState到底是同步还是异步?

    其实setState可能表现为异步更新也可能表现为同步更新

    异步更新情况

    生命周期中

    state = {
        number:1
    };
    componentDidMount(){
        this.setState({number:3})
        console.log(this.state.number)  //输出的是更新前的number --> 1
    }
    

    合成事件中

    首先得了解一下什么是合成事件,react为了解决跨平台,兼容性问题,自己封装了一套事件机制,代理了原生的事件,像在jsx中常见的onClickonChange这些都是合成事件。

    class App extends Component {
      state = { number: 0 }
      increment = () => {
        this.setState({ number: this.state.number + 1 })
        console.log(this.state.number) // 输出的是更新前的number --> 0
      }
      render() {
        return (
          <div onClick={this.increment}>
            {`Counter is: ${this.state.number}`}
          </div>
        )
      }
    }
    

    那如果我们想拿到更新之后的值应该怎么办呢?主要有以下两种方法

    获取setState实时更新过后的值的方法

    回调函数

    setState提供了一个回调函数供开发者使用,在回调函数中,我们可以实时的获取到更新之后的数据

    state = {
        number:1
    };
    componentDidMount(){
        this.setState({number:3},()=>{
            console.log(this.state.number) // 3
        })
    }
    

    这个时候大家可以看到控制台打印的数据就是最新的了,我们也就实时的获取到了最新的数据。

    componentDidUpdate 生命周期

    class App extends Component {
      constructor(props) {
        super(props);
        this.state = {
          number: 0
        }
      }
      render() {
        return (
          <div>
            <h2>当前计数: {this.state.number}</h2>
            <button onClick={e => this.changeText()}>改变数字</button>
          </div>
        )
      }
      componentDidUpdate() {
        // 方式二: 获取异步更新的state
        console.log(this.state.number);
      }
      changeText() {
        this.setState({
          number:this.state.number + 1
        })
      }
    }
    

    为什么在合成事件和生命周期中会表现为异步更新呢?

    归根结底还是因为react框架本身的性能机制所导致的。因为每次调用setState都会触发更新,异步操作是为了提高性能,将多个状态合并一起更新,减少render调用。

    试想一下如果在组件中有以下这样一段代码执行:

    for ( let i = 0; i < 100; i++ ) {
        this.setState( { num: this.state.num + 1 } );
    }
    

    如果setState是一个同步执行的机制,那么这个组件会被重新渲染100次,这对性能是一个相当大的消耗。 显然,React也是想到了这个问题,因此对setState做了一些特殊的优化:

    React会将多个setState的调用合并为一个来执行,也就是说,当执行setState的时候,state中的数据并不会马上更新,所以打印的值,就会得到更新之前的值。

    同步更新情况

    setTimeout

    state = {
        number:1
    };
    componentDidMount(){
        setTimeout(()=>{
          this.setState({number:3})
          console.log(this.state.number) // 3
        },0)
    }
    

    原生事件中

    state = {
        number:1
    };
    componentDidMount() {
        document.body.addEventListener('click', this.changeVal, false);
    }
    changeVal = () => {
        this.setState({
          number: 3
        })
        console.log(this.state.number) // 3
    }
    

    为什么上面这两种情况又表现为同步更新呢?

    原生事件可以简单理解为因为没有走合成事件的那一大堆东西,跳过了react的机制,直接触发click事件,所以当你在原生事件中setState后,能同步拿到更新后的state值。

    setTimeout 可以简单理解为,跳过了react的性能机制,所以也可以同步拿到更新后的state值。

    setState中的批量更新

    export default class App extends Component {
      state = {
        counter: 0
      }
      render() {
        return (
          <div>
            <h2>当前计数: {this.state.counter}</h2>
            <button onClick={e => this.increment()}>+1</button>
          </div>
        )
      }
      increment() {
        // 1.setState本身被合并 不会进行累加 只会加1
         this.setState({
           counter: this.state.counter + 1
         });
         this.setState({
           counter: this.state.counter + 1
         });
         this.setState({
           counter: this.state.counter + 1
         });
      }
    }
    
    • 直接传递对象的setstate会被合并成一次,只会生效一次,只会加 1.

    下面这种写法,就不会被合并,会生效三次。

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

    总结

    • setState在合成事件和生命周期函数中是“异步”的,在原生事件和 setTimeout中是同步的

    • 可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。或者在componentDidUpdate生命周期里面拿到更新后的结果

    • 多次setState更新会合并为一次,如果有相同的更新会被覆盖,只会执行一次

    限制 state 更新视图

    对于类组件如何限制 state 带来的更新作用的呢?

    • pureComponent 可以对 state 和 props 进行浅比较,如果没有发生变化,那么组件不更新。
    • shouldComponentUpdate 生命周期可以通过判断前后 state 变化来决定组件需不需要更新,需要更新返回true,否则返回false。

    起源地下载网 » setState 详解

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元