理解setState(),異步還是同步?

state

state的存在是爲了動態改變組件,比如根據不同的用戶操作和網絡請求,來重新渲染組件。

setState()是React給我們的一個API,用來改變或定義state。

setState()的批量操作(batching)

在一個事件handler函數中,不管setState()被調用多少次,他們也會在函數執行結束以後,被歸結爲一次重新渲染, 可以優化性能, 這個等到最後一起執行的行爲被稱爲batching

所以在函數內的setState()是有序的,如果要更改同一個state key,最後被調用的總會覆蓋之前的。

因爲batching的存在,所以這樣的代碼會和期待有出入。

//假設現在this.state.value = 0;

function eventHandler(){
    this.setState({value:this.state.value + 1});
    this.setState({value:this.state.value + 1});
    this.setState({value:this.state.value + 1});
}

//最後this.state.value仍然會是1,不是3;

所以不能依賴this.state來計算未來狀態。如果想實現這樣的效果,應該傳一個函數給setState。這個函數有兩個參數,第一個爲previous state,第二個爲props。這裏的例子和props無關,只需要第一個參數,所以要達到效果,代碼是這樣

// 假設 this.state = { value: 0 };

function eventHandler(){
    this.setState((state) => ({ value: state.value + 1}));
    this.setState((state) => ({ value: state.value + 1}));
    this.setState((state) => ({ value: state.value + 1}));
}

//現在this.state.value === 3;

到這裏我們得到結論,setState是異步執行的。

如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. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains."

所以當更新state,然後想打印state的時候,應該使用回調。

this.setState({key: val},()=>console.log(this.state));    

所以setState總是異步的,嗎?

當setState()不在事件Handler函數中,如在使用ajax的時候,這種batching的異步表現又不會發生


promise.then(() => {
  // 不在事件函數中,所以setState立刻執行
  this.setState({a: true}); // 重新渲染 {a: true, b: false }
  this.setState({b: true}); // 重新渲染 {a: true, b: true }
});

同步異步要分情況來看:

1. React事件函數使用,像這樣用最常用的形式綁定函數

constructor(props){
    ...
    this.onClick = this.onClick.bind(this);
}

onClick(){
    this.setState({key:val});
}

render(){
    return(
        <div>
            <button onClick = {this.onClick}>Click me</button>
        </div>
}

這裏batching發生,異步表現,是因爲這種常規情景下React “知道”什麼時候退出該事件,什麼時候進行Batch Update原理可以參考這篇很簡潔易懂的文章

2.其他情景,如上面的ajax情景,或這樣用addEventListener綁定函數

componentDidMount(){
    document.querySelector('#btn').addEventListener('click,this.onClick);
}
    
    render(){
        return(
            <div>
                <button id="btn">Click me</button>
            </div>
    }
}

脫離了React的控制,React不知道如何進行Batch Update,setState()就會是同步的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章