ReactMount = {
// ReactDOM.render直接引用此方法
render: function (nextElement, container, callback) {
return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback);
},
// 實際執(zhí)行render的方法
_renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) {
ReactUpdateQueue.validateCallback(callback, 'ReactDOM.render');
// 將傳入的element用TopLevelWrapper包裝索昂,
// 包裝后的元素载庭,標記有rootID挣惰,并且擁有render方法,
// 具體可看TopLevelWrapper的源碼
var nextWrappedElement = React.createElement(TopLevelWrapper, {
child: nextElement
});
// ReactDOM.render方法調(diào)用時链烈,parentComponent為null
var nextContext;
if (parentComponent) {
var parentInst = ReactInstanceMap.get(parentComponent);
nextContext = parentInst._processChildContext(parentInst._context);
} else {
nextContext = emptyObject;
}
// 第一次執(zhí)行時,prevComponent為null挚躯,具體可看此方法源碼
var prevComponent = getTopLevelWrapperInContainer(container);
if (prevComponent) {
var prevWrappedElement = prevComponent._currentElement;
var prevElement = prevWrappedElement.props.child;
// 判斷上一次的prevElement和nextElement是否是同一個組件强衡,或者僅僅是數(shù)字、字符串码荔,如果是漩勤,則直接update,
// 否則目胡,重新渲染整個Element
if (shouldUpdateReactComponent(prevElement, nextElement)) {
var publicInst = prevComponent._renderedComponent.getPublicInstance();
var updatedCallback = callback && function () {
callback.call(publicInst);
};
// 更新vdom
ReactMount._updateRootComponent(prevComponent, nextWrappedElement, nextContext, container, updatedCallback);
return publicInst;
} else {
ReactMount.unmountComponentAtNode(container);
}
}
var reactRootElement = getReactRootElementInContainer(container);
var containerHasReactMarkup = reactRootElement && !!internalGetID(reactRootElement);
var containerHasNonRootReactChild = hasNonRootReactChild(container);
var shouldReuseMarkup = containerHasReactMarkup && !prevComponent && !containerHasNonRootReactChild;
// 本次為首次渲染锯七,因此調(diào)用ReactMount._renderNewRootComponent
var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, nextContext)._renderedComponent.getPublicInstance();
if (callback) {
callback.call(component);
}
return component;
},
/**
- Render a new component into the DOM. Hooked by hooks!
- @param {ReactElement} nextElement element to render
- @param {DOMElement} container container to render into
- @param {boolean} shouldReuseMarkup if we should skip the markup insertion
- @return {ReactComponent} nextComponent
*/
_renderNewRootComponent: function (nextElement, container, shouldReuseMarkup, context) {
ReactBrowserEventEmitter.ensureScrollValueMonitoring();
// 初始化組件實例,并增加組件掛載(mount)誉己、更新(update)眉尸、卸載(unmount)等方法
var componentInstance = instantiateReactComponent(nextElement, false);
// The initial render is synchronous but any updates that happen during
// rendering, in componentWillMount or componentDidMount, will be batched
// according to the current batching strategy.
ReactUpdates.batchedUpdates(batchedMountComponentIntoNode, componentInstance, container, shouldReuseMarkup, context);
var wrapperID = componentInstance._instance.rootID;
instancesByReactRootID[wrapperID] = componentInstance;
return componentInstance;
},
}