你真的會用setState嗎?

setState函數是什麼?

  1. 將須要處理的變化塞入組建的state對象中
  2. 告訴該組件及其子組件須要用更新的狀態來從新渲染
  3. 響應事件處理喝服務端響應更新用戶界面的主要方式

setState經典例子

constructor(props) {
    super(props);
    this.state = {
        count: 0
    };
    this.increase = this.increase.bind(this);
}

increase() {
    this.setState({ count: this.state.count + 1 });
    // 第一次輸出
    console.log('第一次輸出:', this.state.count);
    
    this.setState({ count: this.state.count + 1 });
    // 第二次輸出
    console.log('第二次輸出:', this.state.count);
    
    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);
    }, 1000)
}

不知道大家內心是否有上面代碼的答案了呢?不錯,正確輸出是:0 0 2 3。那可能剛開始學React的童鞋就會問了?爲何前面都是0,後面的正常加了了?那這個setState到底是同步的仍是異步的了?那麼,接下來就爲你解答心中的疑惑=。=vue

合併更新

前兩次的setState,不會當即改變React組件中的state的值,這兩次輸出的都是0;合併更新,將屢次的setState合併成一次,不引起重複渲染異步

setTimeout 同步更新,引起兩次渲染。函數

setState是異步的嗎?

其實,這只是React的障眼法。優化

setState是同步執行的!可是state並不必定會同步更新(異步更新合同步更新都存在)

setState究竟幹了什麼了?this

setState()中有個特別重要的布爾屬性isBatchingUpdates(默認爲false),它決定了state同步更新仍是異步更新spa

setState調用

setState只在合成事件何鉤子函數中是「異步更新」的。

異步更新的背後,是同步代碼處理(「合成事件何鉤子函數」的調用在「更新」前)。code

異步是爲了實現批量更新的手段,也是React新能優化的一種方式。component

爲何直接修改this.state無效

要知道 setState本質是經過一個 隊列機制實現 state更新的。執行 setState時,會將須要更新的 state合併後放入狀態隊列,而不會馬上更新 state,隊列機制能夠 批量更新state。若是不經過 setState而直接修改 this.state,那麼這個 state不會放入狀態隊列中,下次調用 setState時,狀態隊列新進行合併時,會忽略以前直接被修改的 state,這樣咱們就沒法合併了,並且實際也沒有把你想要的 state更新上去。

React.setState中的同步更新

固然了,咱們也是有辦法同步獲取state更新後的值:server

  1. setTimeout等異步操做中調用setState函數
  2. DOM原生事件
  3. 利用setState回調函數
  4. 函數式setState用法

前兩個都是比較好理解,由於沒有前置的batchdUpdate調用,因此isBatchingUpdatesfalse。不會開啓批量更新模式。對象

後面兩個方法,是React自己提供的。要注意的是,setState回調函數要在render函數被從新執行後才執行。

// 回調函數
this.setState({ count: 1 }, () => {
    console.log(this.state.count)
})

// 函數式
this.setState(prevState => {
    return {
        count: prevState.count + 1
    }
})

對比VUE批量更新

Vue在監聽到數據變化後,會開啓一個隊列,並緩衝在同一事件循環中發生的全部數據變動(若是同一個watcher被屢次觸發,只會被推入到隊列中一次)。而後,在下一次事件循環Tick/微任務中,Vue刷新隊列執行實際工做。

vue更新

vue批量更新體現爲:

  1. Mutation Observer(變更觀察器)是偵聽DOM變更的接口。當DOM對象樹發生任何變更時,Mutation Observer會獲得通知。
  2. 概念上,它很接近事件。能夠理解爲,當DOM發生變更會觸發Mutation Observer事件。可是,它與事件有一個本質區別:事件是同步觸發,DOM發生變化會馬上出發響應的事件
  3. Mutation Observer是異步觸發,DOM發生變更,並不會馬上觸發,而是要等到當前全部DOM操做都結束後纔會觸發。

針對以上的知識點,咱們來看看下面這段代碼,看咱們是否理解setState:

class Demo extends React.Component {
  state = {
    count: 0,
  };
  componentDidMount() {
    this.setState({
      count: this.state.count + 1,
    });
    console.log("console: " + this.state.count);

    this.setState({ count: this.state.count + 1 }, () => {
      console.log("console from callback: " + this.state.count);
    });

    this.setState(
      (prevState) => {
        console.log("console from func: " + prevState.count);
        return {
          count: prevState.count + 1,
        };
      },
      () => {
        console.log("last console: " + this.state.count);
      }
    );
  }

  render() {
    console.log("render: " + this.state.count);
    return <h4>test</h4>;
  }
}

總結

  1. state更新須要經過setState,而不能直接操做state
  2. 調用setState更新,state不會馬上生效。
  3. 多個順序執行的setState不是同步一個個執行,會加入到一個隊列中,而後最後一塊兒執行,及批量更新。
相關文章
相關標籤/搜索