本小书部份内容来自做者 Jokcy 的 《React 源码解析》: react.jokcy.me/javascript
感谢 Jokcy 让我深度了解 React。如他所说,在决定阅读 React 源码时认为不会是一件很难的事,可是真正开始阅读以后才发现,事情没那么简单,由于须要足够的耐心、可以独立思考和静下心来(由于你会碰到以前编码没有见过的写法和概念等等)。java
其实 React.Children
这个 API 不多用,能够跳过的,但为何还用一个章节的篇幅去诠释它呢?由于它的源码挺有意思的,对咱们编程设计和编程能力有必定的帮助。react
// ReactChildren.js
...
export {
forEachChildren as forEach,
mapChildren as map,
countChildren as count,
onlyChild as only,
toArray,
};
复制代码
mapChildren
// 上下文需求池里的获取最后一项
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,
};
}
}
// 释放贯穿上下文
function releaseTraverseContext(traverseContext) {
traverseContext.result = null;
traverseContext.keyPrefix = null;
traverseContext.func = null;
traverseContext.context = null;
traverseContext.count = 0;
if (traverseContextPool.length < POOL_SIZE) {
traverseContextPool.push(traverseContext);
}
}
function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
let escapedPrefix = '';
if (prefix != null) {
escapedPrefix = escapeUserProvidedKey(prefix) + '/';
}
// 贯穿上下文
const traverseContext = getPooledTraverseContext(
array,
escapedPrefix,
func,
context,
);
// 贯穿整个子元素
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
// 释放贯穿上下文
releaseTraverseContext(traverseContext);
}
function mapChildren(children, func, context) {
if(children === null) {
return children;
}
const result = [];
mapIntoWithKeyPrefixInternal(children, result, null, func, context);
return result = [];
}
复制代码
补个知识,
map
和forEach
最大区别在于没有return
;编程
先说 getPooledTraverseContext
函数吧,能够理解为上下文对象重用池,主要用于维护一个大小固定的重用池,固然了这个要配合 releaseTraverseContext
使用。ide
每次从这个池子去除一个对象去赋值给 traverseContext
,用完了就用 releaseTraverseContext
去释放而后再丢回池子里。这么作主要是为了提升性能,想一想频繁建立和销毁一个有不少属性的对象是很消耗性能的,你说是否是?(我还能说不嘛,哈哈)函数