React作為一門前端框架,雖然只是focus在MVVM中的View部分,但還是實現了View和model的綁定。修改數據的同時,可以實現View的刷新。這大大簡化了我們的邏輯,只用關心數據流的變化,同時減少了代碼量,使得后期維護也更加方便。這個特性則要歸功于setState()方法。React中利用隊列機制來管理state,避免了很多重復的View刷新。下面我們來從源碼角度探尋下setState機制。
1 還是先聲明一個組件,從最開始一步步來尋源;
class App extends Component { //只在組件重新加載的時候執行一次 constructor(props) { super(props); //.. } //other methods}//ReactBaseClasses.js中如下:這里就是setState函數的來源;//super其實就是下面這個函數function ReactComponent(props, context, updater) { this.props = props; this.context = context; this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the // renderer. this.updater = updater || ReactNoopUpdateQueue;}ReactComponent.prototype.setState = function (partialState, callback) { this.updater.enqueueSetState(this, partialState); if (callback) { this.updater.enqueueCallback(this, callback, 'setState'); }};所以主要來看是否傳入了updater參數,也就是說何時進行 new 組件;具體的updater參數是怎么傳遞進來的,以及是那個對象,參見
react源碼分析系列文章下面的react中context updater到底是如何傳遞的
這里直接說結果,updater對象其實就是ReactUpdateQueue.js 中暴漏出的ReactUpdateQueue對象;
2 既然找到了setState之后執行的動作,我們在一步步深入進去
class Root extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { let me = this; me.setState({ count: me.state.count + 1 }); console.log(me.state.count); // 打印出0 me.setState({ count: me.state.count + 1 }); console.log(me.state.count); // 打印出0 setTimeout(function(){ me.setState({ count: me.state.count + 1 }); console.log(me.state.count); // 打印出2 }, 0); setTimeout(function(){ me.setState({ count: me.state.count + 1 }); console.log(me.state.count); // 打印出3 }, 0); } render() { return ( <h1>{this.state.count}</h1> ) }}ReactComponent.prototype.setState = function (partialState, callback) { this.updater.enqueueSetState(this, partialState); if (callback) { this.updater.enqueueCallback(this, callback, 'setState'); }};ReactUpdateQueue.js
var ReactUpdates = require('./ReactUpdates');function enqueueUpdate(internalInstance) { ReactUpdates.enqueueUpdate(internalInstance);};function getInternalInstanceReadyForUpdate(publicInstance, callerName) { //在ReactCompositeComponent.js中有這樣一行代碼,這就是其來源; // Store a reference from the instance back to the internal representation //ReactInstanceMap.set(inst, this); var internalInstance = ReactInstanceMap.get(publicInstance); //返回的是在ReactCompositeComponent.js中construct函數返回的對象;ReactInstance實例對象并不是簡單的new 我們寫的組件的實例對象,而是經過instantiateReactComponent.js中ReactCompositeComponentWrapper函數包裝的對象;詳見 創建React組件方式以及源碼分析.md return internalInstance;};var ReactUpdateQueue = {//。。。。省略其他代碼 enqueueCallback: function (publicInstance, callback, callerName) { ReactUpdateQueue.validateCallback(callback, callerName); var internalInstance = getInternalInstanceReadyForUpdate(publicInstance); if (!internalInstance) { return null; }//這里將callback放入組件實例的_pendingCallbacks數組中; if (internalInstance._pendingCallbacks) { internalInstance._pendingCallbacks.push(callback); } else { internalInstance._pendingCallbacks = [callback]; } // TODO: The callback here is ignored when setState is called from // componentWillMount. Either fix it or disallow doing so completely in // favor of getInitialState. Alternatively, we can disallow // componentWillMount during server-side rendering. enqueueUpdate(internalInstance); }, enqueueSetState: function (publicInstance, partialState) { var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState'); if (!internalInstance) { return; } //這里,初始化queue變量,同時初始化 internalInstance._pendingStateQueue = [ ] ; //對于 || 的短路運算還是要多梳理下 //queue數組(模擬隊列)中存放著setState放進來的對象; var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []); //這里將partialState放入queue數組中,也就是internalInstance._pendingStateQueue 數組中,此時,每次setState的partialState,都放進了React組件實例對象上的_pendingStateQueue屬性中,成為一個數組; queue.push(partialState); enqueueUpdate(internalInstance); },};module.exports = ReactUpdateQueue;
新聞熱點
疑難解答
圖片精選