ReactChildReconciler模块用于挂载、卸载、或更新ReactDomComponent子组件。
'use strict'; var ReactReconciler = require('./ReactReconciler'); // 用于获取ReactCompositeComponent组件实例或ReactDomComponent组件实例 var instantiateReactComponent = require('./instantiateReactComponent'); // react组件的key值转译 var KeyEscapeUtils = require('./KeyEscapeUtils'); // 由组件的构造函数及key键是否相同,判断是否可以更新组件 var shouldUpdateReactComponent = require('./shouldUpdateReactComponent'); // 用于遍历props.children,触发执行instantiateChild函数,以对象形式获取相关ReactDomComponent组件实例 var traverseAllChildren = require('./traverseAllChildren'); var warning = require('fbjs/lib/warning'); var ReactComponentTreeHook; if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'test') { ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); } // 以集合childInstances获取react组件实例 function instantiateChild(childInstances, child, name, selfDebugID) { var keyUnique = childInstances[name] === undefined; if (process.env.NODE_ENV !== 'production') { if (!ReactComponentTreeHook) { ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook'); } if (!keyUnique) { // ReactComponentTreeHook.getStackAddendumByID当key值相同,获取祖先节点的信息,警告用 process.env.NODE_ENV !== 'production' ? warning(false, 'flattenChildren(...): Encountered two children with the same key, ' + '`%s`. Child keys must be unique; when two children share a key, only ' + 'the first child will be used.%s', KeyEscapeUtils.unescape(name), ReactComponentTreeHook.getStackAddendumByID(selfDebugID)) : void 0; } } if (child != null && keyUnique) { // 获取child对应的react组件实例,表现为ReactCompositeComponent实例或ReactDomComponent实例等 childInstances[name] = instantiateReactComponent(child, true); } } // 用于装载、更新、或卸载ReactDomComponent子组件 // 被ReactMultiChild模块调用,用于管理ReactDomComponent的子组件节点 var ReactChildReconciler = { // 获取props.children相关react组件实例集合 instantiateChildren: function (nestedChildNodes, transaction, context, selfDebugID // 0 in production and for roots ) { if (nestedChildNodes == null) { return null; } var childInstances = {}; if (process.env.NODE_ENV !== 'production') { traverseAllChildren(nestedChildNodes, function (childInsts, child, name) { return instantiateChild(childInsts, child, name, selfDebugID); }, childInstances); } else { traverseAllChildren(nestedChildNodes, instantiateChild, childInstances); } return childInstances; }, // 通过shouldUpdateReactComponent函数判断是否可以更新ReactDomComponent子组件;若不能,卸载组件,并装载新的子组件 // 参数prevChildren组件中先前挂载的子节点,以key键作为标识,用于更新或移除 // 参数nextChildren组件中即将挂载的子节点,以key键作为标识,同prevChildren比较后添加或更新 // 参数mountImages更新为组件最终渲染的子节点图谱 // 参数removedNodes更新为组件待移除的子节点 // 参数transcation生命周期管理 // 参数hostParent父节点信息 updateChildren: function (prevChildren, nextChildren, mountImages, removedNodes, transaction, hostParent, hostContainerInfo, context, selfDebugID // 0 in production and for roots ) { if (!nextChildren && !prevChildren) { return; } var name; var prevChild; for (name in nextChildren) { if (!nextChildren.hasOwnProperty(name)) { continue; } prevChild = prevChildren && prevChildren[name]; var prevElement = prevChild && prevChild._currentElement; var nextElement = nextChildren[name]; if (prevChild != null && shouldUpdateReactComponent(prevElement, nextElement)) { ReactReconciler.receiveComponent(prevChild, nextElement, transaction, context); nextChildren[name] = prevChild; } else { if (prevChild) { removedNodes[name] = ReactReconciler.getHostNode(prevChild); ReactReconciler.unmountComponent(prevChild, false); } var nextChildInstance = instantiateReactComponent(nextElement, true); nextChildren[name] = nextChildInstance; var nextChildMountImage = ReactReconciler.mountComponent(nextChildInstance, transaction, hostParent, hostContainerInfo, context, selfDebugID); mountImages.push(nextChildMountImage); } } for (name in prevChildren) { if (prevChildren.hasOwnProperty(name) && !(nextChildren && nextChildren.hasOwnProperty(name))) { prevChild = prevChildren[name]; removedNodes[name] = ReactReconciler.getHostNode(prevChild); ReactReconciler.unmountComponent(prevChild, false); } } }, // 遍历props.children相关react组件实例,执行unmountComponent方法卸载组件 unmountChildren: function (renderedChildren, safely) { for (var name in renderedChildren) { if (renderedChildren.hasOwnProperty(name)) { var renderedChild = renderedChildren[name]; ReactReconciler.unmountComponent(renderedChild, safely); } } } }; module.exports = ReactChildReconciler;