React源码阅读笔记1

React 版本为 16.8.6(直接看打包后的文件,源代码中文件很分散,建议熟悉流程后在去阅读打包前的代码)
一、
React.createElement:JSX 代码会被 Babel 编译为 React.createElement
react.development.js(line:762)此函数返回createElement包装后的对象
createElement 函数接收 3 个参数,分别是 type, config, children, type 指的是 ReactElement 的类型

1.字符串 div 或 p 等代表原生 DOM,称为 HostComponent;
2.class 类型继承 Component 或 PureComponent 组件的称为 ClassComponent; 方法就是 FunctionalComponent;
3.原生提供的 Fragment、AsyncMode 等是 Symbol,会特殊处理;
4.其他;

function createElement(type, config, children) {
  var propName = void 0;

  // Reserved names are extracted
  var props = {};

  var key = null;
  var ref = null;
  var self = null;
  var source = null;

  if (config != null) {
    // 判断是否有ref属性且ref属性有值 单独取出来
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    if (hasValidKey(config)) {
      key = '' + config.key;
    }

    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    // 把剩余的属性塞到props里面
    for (propName in config) {
      //严谨的判断config对象中是否存在改属性,且属性名不能是react保留的那四种
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }

  // children 的个数
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    //多个孩子  包装成一个数组 挂载到props
    var childArray = Array(childrenLength);
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }

  // 如果type传的东西是个对象,且type有defaultProps这个东西,那就defaultProps的值也塞props里面
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
}

react.development.js(line:296)
updater 在 react-dom 中创建

function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}

Component.prototype.isReactComponent = {};

Component.prototype.setState = function (partialState, callback) {
  !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : void 0;
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

Component.prototype.forceUpdate = function (callback) {
  this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;

function PureComponent(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}
//经典的继承方式   只保留原型上的方法 
var pureComponentPrototype = PureComponent.prototype = new ComponentDummy();
pureComponentPrototype.constructor = PureComponent;
// 属性拷贝  猜测这里是确保兼容性 (不确定)
_assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;

createRef更简单

function createRef() {
  var refObject = {
    current: null
  };
  {
    Object.seal(refObject);
  }
  return refObject;
}

forwardRef:

var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
function forwardRef(render) {
  return {
    $$typeof: REACT_FORWARD_REF_TYPE,
    render: render
  };
}

react.development.js(line:1199)
ReactChildren:

[item, [item, [item]]]经过map()后,平铺成[item,item,item]

function mapChildren(children, func, context) {
  //孩子不存在就返回一个null
  if (children == null) {
    return children;
  }
  var result = [];
  //参数:props.children, [], null, (item)=>{return [item,[item,] ]}, undefined   回调函数由用户传入自定义的
  mapIntoWithKeyPrefixInternal(children, result, null, func, context);
  //经过上面的函数处理,返回出最终渲染的东西
  return result;
}
function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
  var escapedPrefix = '';
  //如果字符串中有连续多个 / 的话,在匹配的字串后再加 /    第二次进入这个函数会用到
  if (prefix != null) {
    escapedPrefix = escapeUserProvidedKey(prefix) + '/';
  }
  var traverseContext = getPooledTraverseContext(array, escapedPrefix, func, context);
  traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
  releaseTraverseContext(traverseContext);
}

先从对象池中取数据getPooledTraverseContext


//对象池   
var POOL_SIZE = 10;
var traverseContextPool = [];
function getPooledTraverseContext(mapResult, keyPrefix, mapFunction, mapContext) {
  //如果对象池内存在对象,则出队一个对象
  if (traverseContextPool.length) {
    var 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
    };
  }
}

mapSingleChildIntoContext:

//bookKeeping:traverseContext=
// {
//  result:[],
//  keyPrefix:'',
//  func:(item)=>{return [item,[item,] ]},
//  context:undefined,
//  count:0,
// }

//child:1

//childKey:.0
function mapSingleChildIntoContext(bookKeeping, child, childKey) {
  var result = bookKeeping.result,
      keyPrefix = bookKeeping.keyPrefix,
      func = bookKeeping.func,
      context = bookKeeping.context;

  //  func  ----> React.Children.map(this.props.children, '----->代表这个函数func' (item)=>{return [item,[item,] ]})
  var mappedChild = func.call(context, child, bookKeeping.count++);
  //如果根据React.Children.map()第二个参数callback,执行仍是一个数组的话,
  //递归调用mapIntoWithKeyPrefixInternal,继续之前的步骤,
  //直到是单个ReactElement
  if (Array.isArray(mappedChild)) {
    //mappedChild:[item,[item,] ]
    //result:[]
    //childKey:.0
    //func:c => c
    mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, function (c) {
      return c;
    });
  } else if (mappedChild != null) { //当mappedChild是单个ReactElement并且不为null的时候
    if (isValidElement(mappedChild)) {
      //赋给新对象除key外同样的属性,替换key属性
      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);
  }
}

traverseAllChildren–> traverseAllChildrenImpl(line:1066):
核心递归函数,目的是展平嵌套数组

function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) {
  var type = typeof children;
  if (type === 'undefined' || type === 'boolean') {
    // All of the above are perceived as null.
    children = null;
  }

  var invokeCallback = false;

  if (children === null) {
    invokeCallback = true;
  } else {
    switch (type) {
      case 'string':
      case 'number':
        invokeCallback = true;
        break;
      case 'object':
        //如果props.children是单个ReactElement/PortalElement的话
        //递归traverseAllChildrenImpl时,12作为child
        //必会触发invokeCallback=true
        switch (children.$$typeof) {
          case REACT_ELEMENT_TYPE:
          case REACT_PORTAL_TYPE:
            invokeCallback = true;
        }
    }
  }

  if (invokeCallback) {
    // callback   ---> mapSingleChildIntoContext
    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.
    //如果只有一个子节点,也将它放在数组中来处理
    //1 key='.0'
    nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar);
    return 1;  //下面有 subtreeCount +=  .....
  }

  var child = void 0;
  var nextName = void 0;
  //有多少个子节点
  var subtreeCount = 0; // Count of children found in the current subtree.
  var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;
  if (Array.isArray(children)) {
    for (var i = 0; i < children.length; i++) {
      child = children[i];
      nextName = nextNamePrefix + getComponentKey(child, i);
      //递归调用
      subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
    }
  } else {
    //判断child是否可迭代
    var iteratorFn = getIteratorFn(children);
    if (typeof iteratorFn === 'function') {
      var iterator = iteratorFn.call(children);
      var step = void 0;
      var 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') {
      ...一些错误警告
    }
  }

  return subtreeCount;
}

你可能感兴趣的:(js)