state的存在是爲了動態改變組件,好比根據不一樣的用戶操做和網絡請求,來從新渲染組件。ajax
setState()是React給咱們的一個API,用來改變或定義state。promise
在一個事件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()不在事件Handler函數中,如在使用ajax的時候,這種batching的異步表現又不會發生。component
promise.then(() => { // 不在事件函數中,因此setState馬上執行 this.setState({a: true}); // 從新渲染 {a: true, b: false } this.setState({b: true}); // 從新渲染 {a: true, b: true } });
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。原理能夠參考這篇很簡潔易懂的文章
componentDidMount(){ document.querySelector('#btn').addEventListener('click,this.onClick); } render(){ return( <div> <button id="btn">Click me</button> </div> } }
脫離了React的控制,React不知道如何進行Batch Update,setState()就會是同步的。