React中setState幾個現象---先知道再理解

常規狀況

在同一個方法中屢次setState是會被合併的,而且對相同屬性的設置只保留最後一次的設置;react

import React from 'react';

export class Test extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
            
        };
    }
    componentWillMount() {
        let me = this;
        me.setState({
            count: me.state.count + 2
        });
        me.setState({
            count: me.state.count + 1
        });
    }
    componentDidMount() {
        let me = this;
        me.setState({
            count: me.state.count + 2
        });
        me.setState({
            count: me.state.count + 1
        });
    }

    onClick() {
        let me = this;
        me.setState({
            count: me.state.count + 1
        });
        me.setState({
            count: me.state.count + 1
        });
    }

    render() {
        console.log(this.state.count);
        console.log('1111111111111111111111111111111111111111111');
        return (
            <div>
                <h1>{this.state.count}</h1>
                <input type="button" value="點擊我" onClick={this.onClick.bind(this)} /><br />
                <br />
            </div>
        )
    }
}

上述執行過程以下:ajax

  1. willmount中的setState會合併成一次執行,count只會保留最後一次的設置,前面的放棄,因此willmount以後是1,並非3;而且在render以前執行,不會引發新的render
  2. render以後執行didMount,setState作一樣的處理,這是count2,而且引發新的render
  3. 點擊按鈕,setState作一樣處理,count3,引發新的render

定時器中的setState

定時器中的setState,每次都會引發新的render,即便是同一個定時器中的屢次setStatejson

代碼更改爲以下:api

componentWillMount() {
        let me = this;
        setTimeout(() => {
            me.setState({
                count: me.state.count + 1
            });
            me.setState({
                count: me.state.count + 1
            });
        }, 0);
    }
    
       componentDidMount() {
        let me = this;
        setTimeout(() => {
            me.setState({
                count: me.state.count + 1
            });
            me.setState({
                count: me.state.count + 1
            });
        }, 0);
    }
    
    onClickTime() {
        let me = this;
        setTimeout(() => {
            me.setState({
                count: me.state.count + 1
            });
            me.setState({
                count: me.state.count + 1
            });
        }, 0);
    }
上述代碼,每次 setState都會引起新的render,須要深刻了解的能夠查查 setState的原理,簡單理解是定時器中的 setState沒走 react的事物機制,執行時批量更新沒被設置 true,因此每次都直接render了。

原生事件中的setState

在按鈕原生事件中定義的 setState,和定時器效果同樣, 每次setState都會引發新的render
react事件是合併的成一次render的。
componentDidMount() {
        this.button.addEventListener('click', this.onClick.bind(this, '原生事件'), false);
 }
    
 onClick(info) {
        console.log(info);
        this.setState({
            count: ++count
        });
        this.setState({
            count: ++count
        });
    }

    render() {
        console.log(this.state.count);
        return <div>
            <input type="button" ref={input => this.button = input} onClick={this.onClick.bind(this, 'React事件')} value="生成計時器" />
            <div>Count:{this.state.count}</div>
        </div>
    }
點擊按鈕,先執行原生事件,再執行react事件,可是原生事件會觸發兩次render,react事件觸發一次。

總結

上述是我對setState的理解,拋磚引玉,但願幫助你們有方向的去了解react原理機制。剛開始接觸,不少同窗想深刻了解,但可能不知道從何入手,這也是我遇到過的困擾,因此如今分享出來,但願能幫助你們少走彎路,更快的、更有準針對性的去研究學習React。promise


如下爲補充內容函數

回調不會觸發react的批量更新機制

其實在回調函數中,setState是不會觸發批量更新機制的,不管是promise,ajax,setTimeout回調等等,同時設置屢次setState,每一個setState都會單獨執行並render,由於上下文發生了變化。學習

下面是驗證codefetch

onClickBtn = () => {
    // const promise = new Promise((resolve, reject) => {
    //   this.setState({ count: this.state.count + 1 });
    //   console.log(this.state.count);
    //   this.setState({ count: this.state.count + 1 });
    //   console.log(this.state.count);
    //   resolve();
    // });

    // promise.then(() => {
    //   this.setState({ count: this.state.count + 1 });
    //   console.log(this.state.count);
    //   this.setState({ count: this.state.count + 1 });
    //   console.log(this.state.count);
    // });

    fetch("/api/getlist")
      .then(response => {
        return response.json();
      })
      .then(data => {
        console.log(JSON.stringify(data));
        this.setState({ count: this.state.count + 1 });
        console.log(this.state.count);
        this.setState({ count: this.state.count + 1 });
        console.log(this.state.count);
      });
  };

生命週期和事件中屢次setState的區別

在寫demo時發現,雖然didMount中的屢次setState會被合併,符合正常的規律,可是經過調試發現,在didMountisBatchingUpdates始終是false,而事件調用觸發的setStateisBatchingUpdates則是truethis

---------------------轉載請標明出處!--------------------

相關文章
相關標籤/搜索