React 源碼解析之React.Children

前言

本小書部份內容來自做者 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 = [];
}
複製代碼

補個知識,mapforEach 最大區別在於沒有 return;編程

先說 getPooledTraverseContext 函數吧,能夠理解爲上下文對象重用池,主要用於維護一個大小固定的重用池,固然了這個要配合 releaseTraverseContext 使用。ide

每次從這個池子去除一個對象去賦值給 traverseContext,用完了就用 releaseTraverseContext 去釋放而後再丟回池子裏。這麼作主要是爲了提升性能,想一想頻繁建立和銷燬一個有不少屬性的對象是很消耗性能的,你說是否是?(我還能說不嘛,哈哈)函數

你能夠

上一篇:React 源碼解析之ReactElementpost

相關文章
相關標籤/搜索