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

state

state的存在是爲了動態改變組件,好比根據不一樣的用戶操做和網絡請求,來從新渲染組件。ajax

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

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文檔所說:this

"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的時候,應該使用回調。code

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

因此setState老是異步的,嗎?

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

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()就會是同步的。

相關文章
相關標籤/搜索