真实的 setState 的过程:
01 02 03 04 05 06 07 08 09 10 11 | setState( partialState ) { // 1. 通过组件对象获取到渲染对象 var internalInstance = ReactInstanceMap.get(publicInstance); // 2. 把新的状态放在渲染对象的 _pendingStateQueue 里面 internalInstance._pendingStateQueue.push( partialState ) // 3. 查看下是否正在批量更新 // 3.1. 如果正在批量更新,则把当前这个组件认为是脏组件,把其渲染对象保存到 dirtyComponents 数组中 // 3.2. 如果可以批量更新,则调用 ReactDefaultBatchingStrategyTransaction 开启更新事务,进行真正的 vdom diff。 // | // v // internalInstance.updateComponent( partialState ) } |
updateComponent 方法的说明:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | updateComponent( partialState ) { // 源码中 partialState 是从 this._pendingStateQueue 中获取的,这里简化了状态队列的东西,假设直接从外部传入 var inst = this ._instance; var nextState = Object.assign( {}, inst.state, partialState ); // 获得组件对象,准备更新,先调用生命周期函数 // 调用 shouldComponentUpdate 看看是否需要更新组件(这里先忽略 props 和 context的更新) if ( inst.shouldComponentUpdate(inst.props, nextState, nextContext) ) { // 更新前调用 componentWillUpdate isnt.componentWillUpdate( inst.props, nextState, nextContext ); inst.state = nextState; // 生成新的 vdom var nextRenderedElement = inst.render(); // 通过上一次的渲染对象获取上一次生成的 vdom var prevComponentInstance = this ._renderedComponent; // render 中的根节点的渲染对象 var prevRenderedElement = prevComponentInstance._currentElement; // 上一次的根节点的 vdom // 通过比较新旧 vdom node 来决定是更新 dom node 还是根据最新的 vdom node 生成一份真实 dom node 替换掉原来的 if ( shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement) ) { // 更新 dom node prevComponentInstance.receiveComponent( nextRenderedElement ) } else { // 生成新的 dom node 替换原来的(以下是简化版,只为了说明流程) var oldHostNode = ReactReconciler.getHostNode( prevComponentInstance ); // 根据新的 vdom 生成新的渲染对象 var child = instantiateReactComponent( nextRenderedElement ); this ._renderedComponent = child; // 生成新的 dom node var nextMarkup = child.mountComponent(); // 替换原来的 dom node oldHostNode.empty(); oldHostNode.appendChild( nextMarkup ) } } } |
接下来看下 shouldUpdateReactComponent 方法:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | function shouldUpdateReactComponent(prevElement, nextElement) { var prevEmpty = prevElement === null || prevElement === false ; var nextEmpty = nextElement === null || nextElement === false ; if (prevEmpty || nextEmpty) { return prevEmpty === nextEmpty; } var prevType = typeof prevElement; var nextType = typeof nextElement; if (prevType === 'string' || prevType === 'number' ) { return (nextType === 'string' || nextType === 'number' ); } else { return ( nextType === 'object' && prevElement.type === nextElement.type && prevElement.key === nextElement.key ); } } |
One Reply to “React 更新视图过程”