React之setState的正確打開方式

React官方文檔中提到:html

NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.react

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.git

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains. setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate().github

If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.less

下面的代碼分別是官方推薦和不推薦的兩種改變state的方式:異步

class Dog extends Component {
    constructor(props) {
        super(props)
        this.state = {
            color: 'white',
            age: 7,
            son: {
              color: 'gray',
              age: 1
            }
        }
    }
    
    brushHair() {
      //right
      setState({color: 'white'})
      
      //wrong
      this.state.color = 'black';
    }
}

但你會發如今實踐中即使使用第二種寫法也不會報任何錯誤,甚至還能獲得預期結果,那麼爲何這種方式會被詬病呢?下面我談談本身的理解:函數

  1. React中state發生變化,組件就會更新。setState()被設計爲異步的,其目的在於在某些狀況下(如一次onClick中)延緩並將屢次更新合併爲一次從而優化組件性能,若是像第二種寫法那樣直接改變state的值,這種優化也就不存在了;性能

  2. 執行setState會按照React設計的執行順序,調用其內部的各類函數,若是直接改變state,這些本應被調用的函數沒有執行,可能會致使奇奇怪怪的錯誤;優化

  3. 由於setState()是異步的,因此上面的代碼最終color的值多是white,顯然不符合正常的思惟邏輯;this

有時候咱們但願在setState以後當即使用state的值,有兩種方法能夠實現這個需求:
方法一:

setState({ color: 'red' }, () => console.log(this.state.color));

即向setState傳入一個回調函數,這個函數會在state發生變化以後被調用。

方法二:

setState({ age: 18 });
setState((prevState, props) => ({
  age: ++prevState.age
}))

setState的第一個參數還能夠是一個函數,這個函數的返回值就是要merge的state,區別在於這個setState會在以前的setState執行完畢後再執行,因此prevState是最新的state。

另外,當更新state的部分屬性時,其餘屬性是不會受影響的,本質上是Object.assign({}, state, partialState),但僅限於第一層結構,若是像下面這樣

brushSonHair() {
    setState({
        son: {
            color: 'black'
        }
    })
}

上面的方法中setState改變的時第二層的屬性值(son中的color),第一層的屬性值(color age)不會受到影響,但son中的age屬性就會丟失(能夠理解爲改變了son)。

相關文章
相關標籤/搜索