setState
的執行是一個 '異步'
的過程,爲何會將這兩個字用引號代替,確定其中有必定的道理,下面對 setState
進行分析javascript
React 源碼,setState
中傳入兩個參數 partialState, callback
:java
partialState
在字面意思理解應該是部分狀態,註釋說明是這樣的 Next partial state or function to produce next partial state to be merged with current state.
,大概翻譯是 下一個部分狀態或函數,以產生下一個要與當前狀態合併的部分狀態。
。實際上,在項目中 this.setState({})
更新指定 state
時,其餘的 state
與當前更新的 state
作了合併。callback
回調函數,意指狀態更新後的回調,在該函數中獲取最新的 state
。setState
處理過程首先調用了 invariant()
, 其次調用了 this.updater.enqueueSetState()
react
/packages/shared/invariant.js
, 這個方法就是判斷 partialState
的類型是否正確,拋出錯誤,附上源碼:git
可是在 V16.7.0版本以前 invariant
拋出的是不一樣類型的錯誤:github
/packages/react-dom/src/server/ReactPartialRenderer.js
,把即將更新的 state
push 到了 queue
中,在 new Component
時,將 updater
傳進去,附上源碼:antd
queue
應該是 React
提高性能的關鍵。由於並非每次調用 setState
, React
都會立馬更新,而是每次調用 setState
, React
只是將其 push 到了待更新的 queue
中,附上源碼:dom
/packages/react-reconciler/src/ReactFiberClassComponent.js
中的 enqueueSetState
;異步
/packages/react-reconciler/src/ReactUpdateQueue.js
中的 enqueueUpdate
;函數
import React from 'react'; import {Button} from 'antd'; class SetState extends React.Component { state = { val: 0 } componentDidMount() { this.setState({ val: this.state.val + 1 }) console.log('鉤子函數:', this.state.val) // 輸出的仍是更新前的值 --> 0 } increment = () => { this.setState({ val: this.state.val + 1 }) console.log('合成方法:', this.state.val) // 輸出的是更新前的val --> 1 } render() { return ( <Button type="primary" onClick={this.increment}> 鉤子函數及合成方法 --> {`Counter is: ${this.state.val}`} </Button> ) } } export default SetState;
import React from 'react'; import {Button} from 'antd'; class SetState extends React.Component { constructor(props) { super(props); this.state = { val: 0 } } componentDidMount() { document.body.addEventListener('click', this.changeValue, false) } changeValue = () => { this.setState({ val: this.state.val + 1 }) console.log('原生js事件:', this.state.val) // 輸出的是更新後的值 --> 1 } render() { return ( <Button type="peimary"> 原生js事件 --> {`Counter is: ${this.state.val}`} </Button> ) } } export default SetState;
import React from 'react'; import {Button} from 'antd'; class SetState extends React.Component { constructor(props) { super(props); this.state = { val: 0 } } componentDidMount() { setTimeout(_ => { console.log('定時器->1:', this.state.val) // 輸出更新前的值 --> 0 this.setState({ val: this.state.val + 1 }) console.log('定時器->2:', this.state.val) // 輸出更新後的值 --> 1 }, 0); console.log('鉤子函數:', this.state.val) // 輸出更新前的值 --> 0 } render() { return ( <Button type="primary"> setTimeout 定時器 --> {`Counter is: ${this.state.val}`} </Button> ) } } export default SetState;
import React from 'react'; import {Button} from 'antd'; class SetState extends React.Component { constructor(props) { super(props); this.state = { val: 0 } } batchUpdates = () => { this.setState({ val: this.state.val + 1 }) this.setState({ val: this.state.val + 1 }) this.setState({ val: this.state.val + 1 }) } render() { return ( <Button type="primary" onClick={this.batchUpdates}> 批量更新 --> {`Counter is: ${this.state.val}`} </Button> ) } } export default SetState;
import React from 'react'; import {Button} from 'antd'; class SetState extends React.Component { constructor(props) { super(props); this.state = { val: 0 } } // 鉤子函數中的 setState 沒法立馬拿到更新後的值; // setState 批量更新的策略; // setTimmout 中 setState 是能夠同步拿到更新結果 componentDidMount() { this.setState({ val: this.state.val + 1 }) console.log('第一步->鉤子函數:', this.state.val); // 0 this.setState({ val: this.state.val + 1 }) console.log('第二步->鉤子函數:', this.state.val); // 0 setTimeout(_ => { this.setState({ val: this.state.val + 1 }) console.log('第三步->定時器:', this.state.val); // 2 this.setState({ val: this.state.val + 1 }) console.log('第四步->定時器:', this.state.val); // 3 }, 0) } render() { return ( <Button type="primary"> 鉤子函數及 setTimmout 定時器 --> {`Counter is: ${this.state.val}`} </Button> ) } } export default SetState;
若是但願在 setState
時就能獲取到最新值,能夠在 setState
的回調函數中獲取最新結果源碼分析
this.setState( { data: newData }, () => { console.log('回調函數中獲取:', me.state.data) } );
setState
所謂的 '異步',實際上只在合成事件一輩子命周期函數中存在,在原生js時間與定時器中任然是同步變化的, setState
中還作了批量更新的優化。若是但願在 this.setState({})
後及時獲取到最新 state
,能夠在其回調函數中獲取。