真实的 setState 的过程:
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 方法的说明:
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 方法:
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 更新视图过程”