ReactElement

The ReactElement module is used to create ReactElements.

In particular, when the React.createElement method is called in the render method of the user-defined component, the ReactCompositeComponent of the container component will be injected into the child component element, which makes it possible to add the current child component element as a ref reference to the container component element.

 

'use strict';

var _assign = require('object-assign');

// Save the container component, that is, the ReactCompositeComponent instance of the user-defined component, and add the need for ref references
var ReactCurrentOwner = require('./ReactCurrentOwner');

// warning(condition,format) condition is no value, replace "%s" in format, and console.error warns
var warning = require('fbjs/lib/warning');

// Can you use the Object.defineProperty method
var canDefineProperty = require('./canDefineProperty');

var hasOwnProperty = Object.prototype.hasOwnProperty;

//symbal or 0xeac7 identifies ReactElementType
var REACT_ELEMENT_TYPE = require('./ReactElementSymbol');

var RESERVED_PROPS = {
  key: true,
  ref: true,
  __self: true,
  __source: true
};

was specialPropKeyWarningShown, specialPropRefWarningShown;

// Verify that the ref is not from the parent component's props.ref
function hasValidRef(config) {
  if (process.env.NODE_ENV !== 'production') {
    if (hasOwnProperty.call(config, 'ref')) {
      var getter = Object.getOwnPropertyDescriptor(config, 'ref').get;
      // getter.isReactWarning is true when the props.ref of the parent component element is added as the ref of the child component element
      if (getter && getter.isReactWarning) {
        return false;
      }
    }
  }
  return config.ref !== undefined;
}

// Verify that the key is not from the parent component's props.key
function hasValidKey(config) {
  if (process.env.NODE_ENV !== 'production') {
    if (hasOwnProperty.call(config, 'key')) {
      var getter = Object.getOwnPropertyDescriptor(config, 'key').get;
      // getter.isReactWarning is true when the props.key of the parent component element is added as the key of the child component element
      if (getter && getter.isReactWarning) {
        return false;
      }
    }
  }
  return config.key !== undefined;
}

// Setting the key property of props is not allowed
function defineKeyPropWarningGetter(props, displayName) {
  var warnAboutAccessingKey = function () {
    if (!specialPropKeyWarningShown) {
      specialPropKeyWarningShown = true;
      process.env.NODE_ENV !== 'production' ?
        warning(false, '%s: `key` is not a prop. Trying to access it will result '
          + 'in `undefined` being returned. If you need to access the same '
          + 'value within the child component, you should pass it as a different '
           + 'prop. (https://fb.me/react-special-props)', displayName)
        : void 0;
    }
  };
  warnAboutAccessingKey.isReactWarning = true;
  Object.defineProperty(props, 'key', {
    get: warnAboutAccessingKey,
    configurable: true
  });
}

// Setting the ref property of props is not allowed
function defineRefPropWarningGetter(props, displayName) {
  var warnAboutAccessingRef = function () {
    if (!specialPropRefWarningShown) {
      specialPropRefWarningShown = true;
      process.env.NODE_ENV !== 'production' ?
        warning(false, '%s: `ref` is not a prop. Trying to access it will result '
          + 'in `undefined` being returned. If you need to access the same '
          + 'value within the child component, you should pass it as a different '
          + 'prop. (https://fb.me/react-special-props)', displayName)
        : void 0;
    }
  };
  warnAboutAccessingRef.isReactWarning = true;
  Object.defineProperty(props, 'ref', {
    get: warnAboutAccessingRef,
    configurable: true
  });
}

// Create ReactElement, ReactElement.createElement is used to convert configuration items
// The parameter type is the constructor of the user-defined component, or the type string of the react-encapsulated native dom component ReactDomElement, such as "div"
// The parameter key is the identifier added when the ReactElement array is created; at the same time, changing the key value can be used to destroy the component instance and regenerate the instance
// The parameter ref is used to make the current ReactElement the ref reference of the upper component element
// The parameter self and parameter source are used for debugging, and are different from the owner container component when printing errors
// The parameter owner top-level container component is injected when React.createElement is called in the render method of the container component
var ReactElement = function (type, key, ref, self, source, owner, props) {
  var element = {
    $$typeof: REACT_ELEMENT_TYPE,//symbal or 0xeac7 identifies ReactElement

    type: type,
    key: key,
    ref: ref,
    props: props,

    // The instance of the top-level container component, in order to set the current component element, that is, the child component element, as the ref reference of the top-level container component, which is used in the ReactRef module under 'react-dom'
    _owner: owner
  };

  if (process.env.NODE_ENV !== 'production') {
    // element._store.validated is used to store the check value of the child node
    element._store = {};

    if (canDefineProperty) {
      Object.defineProperty(element._store, 'validated', {
        configurable: false,
        enumerable: false,
        writable: true,
        value: false
      });
      Object.defineProperty(element, '_self', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: self
      });
      Object.defineProperty(element, '_source', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: source
      });
    } else {
      element._store.validated = false;
      element._self = self;
      element._source = source;
    }
    if (Object.freeze) {
      Object.freeze(element.props);
      Object.freeze(element);
    }
  }

  return element;
};

// Configure the constructor, props, props.children and other properties of the ReactElement element, which are used to create when the component is instantiated, so that the component can be rendered when it is instantiated and mounted.
// The parameter type is the constructor of the user-defined component, the component created by ReactComponent or ReactClass, or the ordinary function returning ReactElement
// Or the string "div", etc., representing the react-wrapped native dom component ReactDomComponent
// The parameter config contains the ref reference information of the subcomponent, and a ReactElement in the key identification array
// and __self property, __source property
// and some attributes in component element props, that is, attributes other than ref, key, __self, __source
// The parameter children is added as the props.children of the component element, and the instantiation of the component can be rendered conditionally
ReactElement.createElement = function (type, config, children) {
  var propName;

  var props = {};

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

  if (config != null) {
    // Verify that the ref is not from the parent component's props.ref
    if (hasValidRef(config)) {
      ref = config.ref;
    }

    // Verify that the key is not from the parent component's props.key
    if (hasValidKey(config)) {
      key = '' + config.key;
    }

    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;

    // Inject properties in config except ref, key, __self, __source into the props of the component element
    for (propName in config) {
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }

  // props.children of the component element from the third parameter
  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];
    }
    if (process.env.NODE_ENV !== 'production') {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    props.children = childArray;
  }

  // Inject defaultProps into props, provided that there is no property of the same name with a true value in props
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }

  // It is not allowed to add key and ref attributes to props, except props are ReactElement
  if (process.env.NODE_ENV !== 'production') {
    if (key || ref) {
      if (typeof props.$$typeof === 'undefined' || props.$$typeof !== REACT_ELEMENT_TYPE) {
        var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;
        if (key) {
          defineKeyPropWarningGetter(props, displayName);
        }
        if (ref) {
          defineRefPropWarningGetter(props, displayName);
        }
      }
    }
  }

  // create ReactElement
  // ReactCurrentOwner.current is an instance of the top-level container component, which is used in the ReactRef module under 'react-dom' to set the current component element, that is, the child component element, as the ref reference of the top-level container component
  // That is, calling the React.createElement method in the render method of the user-defined component makes ReactCurrentOwner.current a true value
  return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
};

// Create a factory function for component elements, predefine the component's constructor type
ReactElement.createFactory = function (type) {
  var factory = ReactElement.createElement.bind(null, type);
  factory.type = type;
  return factory;
};

// Replace the key of the original component element
ReactElement.cloneAndReplaceKey = function (oldElement, newKey) {
  var newElement = ReactElement(oldElement.type, newKey, oldElement.ref, oldElement._self, oldElement._source, oldElement._owner, oldElement.props);

  return newElement;
};

// Create ReactElement in copy form
// Parameter element ReactElement to be copied
// The parameter config={ref,key,propName} resets the ref, key and some props of the new component element
// The parameter children is used as props.children of the component element
ReactElement.cloneElement = function (element, config, children) {
  var propName;

  var props = _assign({}, element.props);

  var key = element.key;
  var ref = element.ref;
  var self = element._self;
  var source = element._source;
  var owner = element._owner;

  if (config != null) {
    // reset ref, also reset ref
    if (hasValidRef(config)) {
      ref = config.ref;
      owner = ReactCurrentOwner.current;
    }

    // reset key
    if (hasValidKey(config)) {
      key = '' + config.key;
    }

    // Add default defaultProps and props configuration in config
    var 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];
        }
      }
    }
  }

  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;
  }

  return ReactElement(element.type, key, ref, self, source, owner, props);
};

// Determine whether ReactElement is ReactElement by the $$typeof flag
ReactElement.isValidElement = function (object) {
  return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
};

module.exports = ReactElement;

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326929800&siteId=291194637