Children.map
function mapChildren(children, func, context) { // 如果遍历的 children 为空则直接返回,包括 undefined if (children == null) { return children; } // 创建用于存储结果的数组,最后返回 const result = []; mapIntoWithKeyPrefixInternal(children, result, null, func, context); return result;}// 带着内部 key 值前缀进行映射?function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { // 默认前缀 let escapedPrefix = ''; // 如果传入的前缀不为空,转义后存入 escapedPrefix if (prefix != null) { escapedPrefix = escapeUserProvidedKey(prefix) + '/'; } const traverseContext = getPooledTraverseContext( array, escapedPrefix, func, context, ); // 遍历所有 children traverseAllChildren(children, mapSingleChildIntoContext, traverseContext); releaseTraverseContext(traverseContext);}const POOL_SIZE = 10;const traverseContextPool = [];function getPooledTraverseContext( mapResult, keyPrefix, mapFunction, mapContext,) { if (traverseContextPool.length) { // 如果上下文缓存中已经有内容 const traverseContext = traverseContextPool.pop(); traverseContext.result = mapResult; traverseContext.keyPrefix = keyPrefix; traverseContext.func = mapFunction; traverseContext.context = mapContext; traverseContext.count = 0; return traverseContext; } else { // 如果缓存中没有已存在的上下文则直接返回 return { result: mapResult, keyPrefix: keyPrefix, func: mapFunction, context: mapContext, count: 0, }; }}// 如果 children 为空,则直接返回function traverseAllChildren(children, callback, traverseContext) { if (children == null) { return 0; } return traverseAllChildrenImpl(children, '', callback, traverseContext);}function traverseAllChildrenImpl( children, nameSoFar, callback, traverseContext,) { const type = typeof children; // undefined 和 boolean 回归至 null if (type === 'undefined' || type === 'boolean') { // All of the above are perceived as null. children = null; } // 是否调用回调函数 let invokeCallback = false; // 如果 children 是无效值或者是单值或者是组件,则确认直接调用回调即可 if (children === null) { invokeCallback = true; } else { switch (type) { case 'string': case 'number': invokeCallback = true; break; case 'object': switch (children.$$typeof) { case REACT_ELEMENT_TYPE: case REACT_PORTAL_TYPE: invokeCallback = true; } } } // 如果可以直接调用回调函数,则直接调用回调,并返回 if (invokeCallback) { callback( traverseContext, children, // If it's the only child, treat the name as if it was wrapped in an array // so that it's consistent if the number of children grows. // 如果 nameSoFar === '',说明所遍历只是单个节点,所以 nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar, ); return 1; } let child; let nextName; let subtreeCount = 0; // Count of children found in the current subtree. const nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR; // 如果 children 是数组,则遍历数组, if (Array.isArray(children)) { for (let i = 0; i < children.length; i++) { child = children[i]; nextName = nextNamePrefix + getComponentKey(child, i); subtreeCount += traverseAllChildrenImpl( child, nextName, callback, traverseContext, ); } } else { const iteratorFn = getIteratorFn(children); if (typeof iteratorFn === 'function') { const iterator = iteratorFn.call(children); let step; let ii = 0; while (!(step = iterator.next()).done) { child = step.value; nextName = nextNamePrefix + getComponentKey(child, ii++); subtreeCount += traverseAllChildrenImpl( child, nextName, callback, traverseContext, ); } } else if (type === 'object') { let addendum = ''; const childrenString = '' + children; invariant( false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum, ); } } return subtreeCount;}function mapSingleChildIntoContext(bookKeeping, child, childKey) { const {result, keyPrefix, func, context} = bookKeeping; let mappedChild = func.call(context, child, bookKeeping.count++); if (Array.isArray(mappedChild)) { mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c); } else if (mappedChild != null) { if (isValidElement(mappedChild)) { mappedChild = cloneAndReplaceKey( mappedChild, // Keep both the (mapped) and old keys if they differ, just as // traverseAllChildren used to do for objects as children keyPrefix + (mappedChild.key && (!child || child.key !== mappedChild.key) ? escapeUserProvidedKey(mappedChild.key) + '/' : '') + childKey, ); } result.push(mappedChild); }}
Children.forEach
function forEachChildren(children, forEachFunc, forEachContext) { if (children == null) { return children; } const traverseContext = getPooledTraverseContext( null, null, forEachFunc, forEachContext, ); traverseAllChildren(children, forEachSingleChild, traverseContext); releaseTraverseContext(traverseContext);}
Children.count
function countChildren(children) { return traverseAllChildren(children, () => null, null);}
Children.only
function onlyChild(children) { invariant( isValidElement(children), 'React.Children.only expected to receive a single React element child.', ); return children;}
toArray
function toArray(children) { const result = []; mapIntoWithKeyPrefixInternal(children, result, null, child => child); return result;}