React 源码解析之React.Children

其实 React.Children 这个 API 很少用,可以跳过的,但为什么还用一个章节的篇幅去诠释它呢?因为它的源码挺有意思的,对我们编程设计和编程能力有一定的帮助。

上源码

// 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 = [];
}
复制代码

补个知识,mapforEach 最大区别在于没有 return;

先说 getPooledTraverseContext 函数吧,可以理解为上下文对象重用池,主要用于维护一个大小固定的重用池,当然了这个要配合 releaseTraverseContext 使用。

每次从这个池子去除一个对象去赋值给 traverseContext,用完了就用 releaseTraverseContext 去释放然后再丢回池子里。这么做主要是为了提高性能,想想频繁创建和销毁一个有很多属性的对象是很消耗性能的,你说是不是?(我还能说不嘛,哈哈)

你可以

上一篇:React 源码解析之ReactElement

转载于:https://juejin.im/post/5cc9c06ee51d453acd5050a7

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值