# ReactElement

文件地址:react/src/ReactElement.js

处理React虚拟DOM的创建/复制/校验等逻辑。

# createElement/jsx

用于创建React Element,但createElement函数本身只是解析标签属性。

jsx和createElement是完全一致的。

/**
 * @param {*} type 标签名
 * @param {Object} config 标签属性
 * @param {string | ReactElement | array} children 子DOM
 */
function createElement(type, config, children) {
  let propName;
  
  const props = {}; // 提取内建标签属性,key、ref、__self、__source
  
  let key = null; // 组件索引值,用于重渲染标识
  let ref = null; // DOM引用
  let self = null;
  let source = null;
  
  // 处理标签属性
  if (config != null) {
    // 校验标签是否存在ref属性并记录ref值
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    
    // 过滤标签是否存在key属性并将key值转为字符串记录下来
    if (hasValidKey(config)) {
      key = '' + config.key
    }
    
    // self和source如果没有默认值,则赋值为null
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config__source;
    
    // 剩余标签属性放在props中
     for (propName in config) {
       // 提取标签自有属性并过滤内建标签属性
       if (
         hasOwnProperty.call(config, propName) &&
         !RESERVED_PROPS.hasOwnProperty(propName)
       ) {
         props[propName] = config[propName];
       }
     }
  }
  
  // 处理children
  const childrenLength = arguments.length - 2;
  // 传输了children参数
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    // 传送了多个children参数,createElement支持如下调用方式,会合并为数组
    // createElement(type, config, children, children, children);
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2]; // children下标从2开始
    }
    props.children = childArray;
  }
  
  // 处理默认props
  // Component.defaultProps = { xxx: xxx }
  if (type && type.defaultProps) {
    const 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,
  );
}

# ReactElement

React Element组件。

const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    $$typeof: REACT_ELEMENT_TYPE, // React Element标识
    
    type: type,
    key: key,
    ref: ref,
    props: props,
    
    _owner: owner,
  };
  
  return element;
};

# cloneElement

function cloneElement(element, config, children) {
  let propName;
  
  // 原始props拷贝
  const props = Object.assign({}, element.props);
  
  let key = element.key;
  let ref = element.ref;
  
  // 
  const self = element._self;
  const source = element._source;
  let owner = element._owner;
  
  // 处理标签属性
  if (config != null) {
    // 校验标签是否存在ref属性并记录ref值
    if (hasValidRef(config)) {
      ref = config.ref;
      owner = ReactCurrentOwner.current;
    }
    
    // 校验标签是否存在key属性并记录key值
    if (hasValidKey(config)) {
      key = '' + config.key;
    }
    
    // 默认props拷贝
    let defaultProps;
    if (element.type && element.type.defaultProps) {
      defaultProps = element.type.defaultProps;
    }
    // 标签属性复制
    for (propName in config) {
      if (
      	hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        if (config[propName] === undefined && defaultProps !== undefined) {
          props[propName] = defaultProps[propName];
        } else {
          props[propName] = config[propName];
        }
      }
    }
  }
  
  // 子节点复制
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    const childrenArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }
  
  return ReactElement(element.type, key, ref, self, source, owner, props);
}

# createFactory

创建React Element元素,已经被createElement替代了。

function createFactory(type) {
  const factory = createElement.bind(null, type);
  factory.type = type;
  return factory;
}

# isValidElement

校验是否为React Element并且防止XSS。

function isValidElement(object) {
  return (
  	typeof object === 'object' &&
    object !== null &&
    object.$$typeof === REACT_ELEMENT_TYPE
  );
}
最近更新时间: 2023/8/22 17:55:30