React之setState

林尋丶發表於2018-07-20

使用過React的使用者都知道setState是一個管理state的重要方法,下面簡單介紹下這個API。

setState不會立即改變元件中state的值

我們知道,this.state是隻讀的,更新狀態不能直接修改,而是通過this.setState方法。這是為什麼呢?this.state只是一個物件,我們修改它的值是沒有意義的。仔細想一想,我們之所以要修改state,無非是為了改變頁面的渲染狀態;所以React設計setState方法就是為了重新渲染頁面。

我們可以在setState之後列印一下this.state的值,會發現它並沒有改變,還是之前的值。如果我們需要在短時間內多次setState,並且每次setState的值跟之前的狀態有關,我們就需要使用函式作為setState的引數了,這個函式引數接收兩個引數(當前的state和當前的props)。舉個例子:

// 可能最終產生的結果是this.state.value只增加了1
function test1() {
    this.setState({ value: this.state.value + 1 });
    this.setState({ value: this.state.value + 1 });
    this.setState({ value: this.state.value + 1 });
}

// 換種寫法,結果就如我們所意了
function test2() {
    this.setState((state, props) => ({ value: state.value + 1 }));
    this.setState((state, props) => ({ value: state.value + 1 }));
    this.setState((state, props) => ({ value: state.value + 1 }));
}
複製程式碼

因為使用函式式setState,React會保證每次呼叫函式時,state都已經合併了之前的狀態修改結果。

setState還有第二個引數callback,所以下面這種寫法也是可以的:

this.setState({ value: this.state.value + 1 }, (val) => {
  this.setState({ value: this.state.value + 1 }, () => {
    this.setState({ value: this.state.vavlue + 1 });
  });
});
複製程式碼

我個人還是比較傾向於函式式setState的寫法。

貌似有時候setState也會同步更新state,比如使用setTimeout/setInterval或者addEventListener處理事件。具體參考setState何時同步更新狀態

多次setState會合並

前面我們瞭解到setState並不會立即改變state的值,而是將其放到一個任務佇列裡,最終將多個setState合併,一次性更新頁面。所以我們可以在程式碼裡多次呼叫setState,每次只需要關注當前修改的欄位即可。

另外,需要注意的是,setState觸發頁面重新渲染需要經過以下生命週期:

  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

經過測試,其實state的值只有在render的時候才真正被修改了,在shouldComponentUpdate和componentWillUpdate時還是之前的值。測試結果如下:

// shouldComponentUpdate: 0
// componentWillUpdate: 0
// render: 1
// componentDidUpdate: 1
// shouldComponentUpdate: 1
// componentWillUpdate: 1
// render: 2
// componentDidUpdate: 2
// shouldComponentUpdate: 2
// componentWillUpdate: 2
// render: 3
// componentDidUpdate: 3
複製程式碼

參考:setState:這個API設計到底怎麼樣

相關文章