4

阅读react源码--ReactElement部分

 2 years ago
source link: https://snayan.github.io/post/reactelement_source/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

阅读react源码--ReactElement部分

May 30, 2017/「 react 」/ Edit on Github ✏️

ReactElement 对象为 React 提供了createElementcreateFactorycloneElementisValidElement四个方法。ReactElement 是一个工厂方法,不是类模式,不要使用new去调用。检查一个对象是否是 react element 对象,通过检查这个对象的$$typeof是否等于Symbol.for('react.element')

var ReactElement=function(type,key,ref,self,source,owner,props){
  var element={
	$$typeof:REACT_ELEMENT_TYPE,// Symbol['for']('react.element')
    type:type,
    key:key,
    ref:ref,
    props:props,
    _owner:owner
  };
  if(process.env.NODE_ENV!=='production'{
      // ....... 增加一些其他的属性
      if(Object.freeze){
      Object.freeze(element.props);
      Object.freeze(element);
    }
  })
  return element;
}
  • createElement,第一个参数是type,实际是一个 Component 的构造函数,在type.defaultProps上定义默认的props值;第二个参数config是一个对象或者null,对象提供了props名,也可以提供keyref__self__source,第三个参数及后续的参数是children
ReactElement.createElement=function(type,config,children){
  var propName;
  var props={};
  var key=null,ref=null,self=null,source=null;
  if(config!=null){
    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;
  // 赋值config里配置的props
  for(propName in config){
    if(hasOWnProperty.call(config,propName) && !['key','ref','__selft','__source'].includes(propName)){
      props[propName]=config[propName];
    }
  }
  // 赋值props.children
  var childrenLength=arguments.length-2;
  if(childrenLength===1){
    props.children=children;
  }else if(childrenLength>1){
    var childArray=Array(childrenLength);
    for(var i=0;i<childrenLength;i++){
      childArray[i]=arguments[i+2];
    }
    props.children=childArray;
  }
  // 赋值props的默认值
  if(type && type.defaultProps){
    var defaultProps=type.defaultProps;
    for(propName in defaultProps){
      if(props[propName]===undefined){
        props[propName]=defaultProps[propName];
      }
    }
  }
  // .... 非开发环境配置
  // 返回react elment
  return ReactElement(type,key,ref,self,source,ReactCurrentOwner.current,props);
}
  • createFactory,这个方法返回一个创建 react element 的函数。接受一个参数,type,用于指定要创建的 element 的类型。
ReactElement.createFactory = function(type) {
  var factory = ReactElemet.createElement.bind(null, type)
  factory.type = type
  return factory
}
  • cloneElement,这个方法用于克隆一个已存在的 element,第一个参数就是element,用于被复制的,第二个是config,第三个是children,第二个和第三个参数与createElement意义一样,用于设置 props 和 children 的。其中,如果指定了 config,则会覆盖原 element 中的 props,如果指定了 children,则同样会覆盖原 element 的 children。
ReactElement.cloneElement = function(element, config, children) {
  var propName
  // 先复制原element的props和key,ref.
  var props = _assign({}, element.props)
  var key = element.key,
    ref = element.ref
  var self = element._self,
    source = element._source,
    owner = element._owner
  // 如果config不为null,则覆盖原element的props和,key,self..
  if (config != null) {
    if (hasValidRef(config)) {
      ref = config.ref
      owner = ReactCurrentOwner.cuurent
    }
    if (hasValidKey(config)) {
      key = config.key
    }
    var defaultProps
    if (element.type && element.defaultProps) {
      defaultProps = element.type.defaultProps
    }
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !["key", "ref", "__self", "__source"].includes(propName)
      ) {
        if (
          config[propName] === undefined &&
          defaultProps[propName] !== undefined
        ) {
          props[propName] = defaultProps[propName]
        } else {
          props[propName] = config[propName]
        }
      }
    }
  }
  // 如果children不为null,则重新指定新的element的children
  var childrenLength = arguments.length - 2
  if (childrenLength === 1) {
    props.children = children
  } else if (childrenLength > 1) {
    var childArray = Array(childrenLength)
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2]
    }
    props.children = childArray
  }

  // 最后也是使用ReactElement工厂创建新的react element
  return ReactElement(element.type, key, ref, self, source, owner, props)
}
  • isValidElement,这个方法是用于来判断一个对象是否是 react element 对象。判断的依据就是 react element 的对象会有一个属性$$typeof,它等于Symbol['for']('react.element')
ReactElement.isValidElement = function(object) {
  return (
    typeof object === "object" &&
    object !== null &&
    object.$$typeof === Symbol["for"]("react.element")
  )
}

「react 版本 15.5.4」


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK