ReactDOM.js
var ReactDOM = {
findDOMNode: findDOMNode,
render: ReactMount.render,
unmountComponentAtNode: ReactMount.unmountComponentAtNode,
version: ReactVersion,
/* eslint-disable camelcase */
unstable_batchedUpdates: ReactUpdates.batchedUpdates,
unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer
/* eslint-enable camelcase */
};
ReactDOM.render()
ReactDOM.render()方法来自ReactMount文件的render方法:
render: function (nextElement, container, callback) {
return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback);
},
Render()将子树nextElement注入到指定的container中,并调用其回调方法_renderSubtreeIntoContainer,它将完成
(1)React.createElement 生成待插入节点的虚拟DOM实例对象
(2)对新旧虚拟DOM进行对比,找到需要更新的地方批量改动。初次渲染直接将虚拟DOM转换为真实DOM
(3)将DOM插入到container中
Diff 算法
简单mark一下(详细了解需要去看专门的文档):
1.不同的节点类型 直接删去旧的节点,新建一个新的节点。
2.相同节点类型 如果没有key对比它们的属性,只改变需要改变的属性,如果配置了key将作为唯一的节点不是改变其属性,而是直接操作此节点。
_renderSubtreeIntoContainer
_renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) {
/*
*将callback放入到React的更新队列中,判断nextElement有效性以及当前是发开环境还是生产环境。(代码省略)
*/
…
var nextWrappedElement = React.createElement(TopLevelWrapper, { child: nextElement });
// 返回一个ReactElement实例对象,也就是虚拟DOM的实例对象,下面就要把它渲染出来
var nextContext;
/*(1)判断是否有parentComponent,如果有则将其写到parentComponent*/
if (parentComponent) {
var parentInst = ReactInstanceMap.get(parentComponent);
nextContext = parentInst._processChildContext(parentInst._context);
} else {
nextContext = emptyObject;
}
var prevComponent = getTopLevelWrapperInContainer(container);
/*
*(2)判断是否有prevComponent,如果有则取其child,利用Diff算法判断是否需要更新,如果需要则调用_updateRootComponen 方法,并return结果。对于初次渲染不需要该过程。
*/
if (prevComponent) {
var prevWrappedElement = prevComponent._currentElement;
var prevElement = prevWrappedElement.props.child;
// shouldUpdateReactComponent方法判断是否需要更新,对同一DOM进行比较,type相同,key(如果有)相同的组件做DOM diff
if (shouldUpdateReactComponent(prevElement, nextElement)) {
var publicInst = prevComponent._renderedComponent.getPublicInstance();
var updatedCallback = callback && function () {
callback.call(publicInst);
};
ReactMount._updateRootComponent(prevComponent, nextWrappedElement, nextContext, container, updatedCallback);
return publicInst;
} else {
ReactMount.unmountComponentAtNode(container);
}
}
/*
*(3)对于prevElement为null直接跳到此步
var reactRootElement = getReactRootElementInContainer(container);
var containerHasReactMarkup = reactRootElement && !!internalGetID(reactRootElement);
var containerHasNonRootReactChild = hasNonRootReactChild(container);
var shouldReuseMarkup = containerHasReactMarkup && !prevComponent && !containerHasNonRootReactChild;
/*
*3核心部分,调用_renderNewRootComponent,_renderedComponent,getPublicInstance三个方法,
*/
var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, nextContext)._renderedComponent.getPublicInstance();
if (callback) {
callback.call(component);
}
return component;
}
网友评论