packages/react/ReactElement.js 해석

13207 단어

APIs


createElement

React.createElement(
  type,
  [props],
  [...children]
)

지정된 유형의 React element를 생성하고 반환합니다.type 매개 변수는 탭 문자열 (예: 'div' 이나 'span', React component 구성 요소 (a class or a function), React fragment 형식일 수 있습니다.

cloneElement

React.cloneElement(
  element,
  [props],
  [...children]
)

복제하고 새로운react-element를 되돌려줍니다.반환된 새 reactElement에는 원래 요소의 속성이 있으며, 새로 부여된 속성은 원래 속성과 얕게 병합됩니다.새 서브어셈블리가 원래 서브어셈블리를 대체합니다.키와ref 속성이 보존됩니다.
React.cloneElement()는 다음과 같습니다.
{children}

그러나 이것도 구성 요소의ref를 보존합니다.이것은 리프를 통해 하위 노드를 얻을 때, 당신의 조상 노드에서 의외로 그것을 훔치지 않을 것이라는 것을 의미한다.같은 ref가 클론 후의 새 요소에 추가됩니다.

createFactory

React.createFactory(type)

지정된 유형의 React 요소를 생성하는 함수를 반환합니다.React.createElement()와 비슷한 것은 형식 매개 변수는 탭 이름 문자열 (예: 'div' 이나 'span', React 구성 요소 형식 (class 구성 요소나 함수 구성 요소), React fragment 형식일 수도 있다.
이 보조 함수는 사용되지 않으므로 JSX 또는 직접 호출React.createElement()을 사용하여 대체하는 것이 좋습니다.

isValidElement()

React.isValidElement(object)

객체가 React 요소인지 확인하고 반환 값이 true 또는 false인지 확인합니다.

소스 해석:


some utils:

import invariant from 'shared/invariant';
import warningWithoutStack from 'shared/warningWithoutStack';
import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';

import ReactCurrentOwner from './ReactCurrentOwner';

const hasOwnProperty = Object.prototype.hasOwnProperty;

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

let specialPropKeyWarningShown, specialPropRefWarningShown;

function hasValidRef(config) {
  if (__DEV__) {
    if (hasOwnProperty.call(config, 'ref')) {
      const getter = Object.getOwnPropertyDescriptor(config, 'ref').get;
      if (getter && getter.isReactWarning) {
        return false;
      }
    }
  }
  return config.ref !== undefined;
}

function hasValidKey(config) {
  if (__DEV__) {
    if (hasOwnProperty.call(config, 'key')) {
      const getter = Object.getOwnPropertyDescriptor(config, 'key').get;
      if (getter && getter.isReactWarning) {
        return false;
      }
    }
  }
  return config.key !== undefined;
}

function defineKeyPropWarningGetter(props, displayName) {
  const warnAboutAccessingKey = function() {
    if (!specialPropKeyWarningShown) {
      specialPropKeyWarningShown = true;
      warningWithoutStack(
        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,
      );
    }
  };
  warnAboutAccessingKey.isReactWarning = true;
  Object.defineProperty(props, 'key', {
    get: warnAboutAccessingKey,
    configurable: true,
  });
}

function defineRefPropWarningGetter(props, displayName) {
  const warnAboutAccessingRef = function() {
    if (!specialPropRefWarningShown) {
      specialPropRefWarningShown = true;
      warningWithoutStack(
        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,
      );
    }
  };
  warnAboutAccessingRef.isReactWarning = true;
  Object.defineProperty(props, 'ref', {
    get: warnAboutAccessingRef,
    configurable: true,
  });
}
  • RESERVED_PROPS 보존 속성: ReactElement을 구성할 때 config 파라미터에 보존 속성이 있으면 이 속성들은 단독으로 추출되어 파라미터로 별도로 전송됩니다ReactElement()
  • hasValidRefhasValidKey:config 매개 변수에 속성을 보존하는 두 가지 도구 방법이 있는지 판단합니다.
  • defineKeyPropWarningGetterdefineRefPropWarningGetterref와 키라는 두 가지 특수한 속성에 대해react는 개발자가props에서 직접 가져오는 것을 허용하지 않으며 개발 환경에서 경고 로그를 보냅니다.

  • 핵심 API

    /**
     * Factory method to create a new React element. This no longer adheres to
     * the class pattern, so do not use new to call it. Also, no instanceof check
     * will work. Instead test $$typeof field against Symbol.for('react.element') to check
     * if something is a React Element.
     *
     * @param {*} type
     * @param {*} props
     * @param {*} key
     * @param {string|object} ref
     * @param {*} owner
     * @param {*} self A *temporary* helper to detect places where `this` is
     * different from the `owner` when React.createElement is called, so that we
     * can warn. We want to get rid of owner and replace string `ref`s with arrow
     * functions, and as long as `this` and owner are the same, there will be no
     * change in behavior.
     * @param {*} source An annotation object (added by a transpiler or otherwise)
     * indicating filename, line number, and/or other information.
     * @internal
     */
    const ReactElement = function(type, key, ref, self, source, owner, props) {
      const element = {
        // This tag allows us to uniquely identify this as a React Element
        $$typeof: REACT_ELEMENT_TYPE,
    
        // Built-in properties that belong on the element
        type: type,
        key: key,
        ref: ref,
        props: props,
    
        // Record the component responsible for creating this element.
        _owner: owner,
      };
    
      if (__DEV__) {
        // The validation flag is currently mutative. We put it on
        // an external backing store so that we can freeze the whole object.
        // This can be replaced with a WeakMap once they are implemented in
        // commonly used development environments.
        element._store = {};
    
        // To make comparing ReactElements easier for testing purposes, we make
        // the validation flag non-enumerable (where possible, which should
        // include every environment we run tests in), so the test framework
        // ignores it.
        Object.defineProperty(element._store, 'validated', {
          configurable: false,
          enumerable: false,
          writable: true,
          value: false,
        });
        // self and source are DEV only properties.
        Object.defineProperty(element, '_self', {
          configurable: false,
          enumerable: false,
          writable: false,
          value: self,
        });
        // Two elements created in two different places should be considered
        // equal for testing purposes and therefore we hide it from enumeration.
        Object.defineProperty(element, '_source', {
          configurable: false,
          enumerable: false,
          writable: false,
          value: source,
        });
        if (Object.freeze) {
          Object.freeze(element.props);
          Object.freeze(element);
        }
      }
    
      return element;
    };
    

    ReactElement 함수는 ReactElement 대상을 정의하고 ReactElement 대상을 되돌려줍니다. 이 대상에는ref,key,props 등의 속성이 있습니다.또한 개발 환경에서는 개발자가 debug this 지침과 오류를 판단할 때 포지셔닝 코드를 추가하는 데 사용될 수 있습니다.추가 정의_self 속성이 일일이 열거할 수 없는 이유는 테스트를 할 때 테스트 용례를 쓰기 편하고 요소 대상을 동결할 수 있기 때문이다.

    createElement

    /**
     * Create and return a new ReactElement of the given type.
     * See https://reactjs.org/docs/react-api.html#createelement
     */
    export function createElement(type, config, children) {
      let propName;
    
      // Reserved names are extracted
      const props = {};
    
      let key = null;
      let ref = null;
      let self = null;
      let 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;
        // Remaining properties are added to a new props object
        for (propName in config) {
          if (
            hasOwnProperty.call(config, propName) &&
            !RESERVED_PROPS.hasOwnProperty(propName)
          ) {
            props[propName] = config[propName];
          }
        }
      }
    
      // Children can be more than one argument, and those are transferred onto
      // the newly allocated props object.
      const childrenLength = arguments.length - 2;
      if (childrenLength === 1) {
        props.children = children;
      } else if (childrenLength > 1) {
        const childArray = Array(childrenLength);
        for (let i = 0; i < childrenLength; i++) {
          childArray[i] = arguments[i + 2];
        }
        if (__DEV__) {
          if (Object.freeze) {
            Object.freeze(childArray);
          }
        }
        props.children = childArray;
      }
    
      // Resolve default props
      if (type && type.defaultProps) {
        const defaultProps = type.defaultProps;
        for (propName in defaultProps) {
          if (props[propName] === undefined) {
            props[propName] = defaultProps[propName];
          }
        }
      }
      if (__DEV__) {
        if (key || ref) {
          const displayName =
            typeof type === 'function'
              ? type.displayName || type.name || 'Unknown'
              : type;
          if (key) {
            defineKeyPropWarningGetter(props, displayName);
          }
          if (ref) {
            defineRefPropWarningGetter(props, displayName);
          }
        }
      }
      return ReactElement(
        type,
        key,
        ref,
        self,
        source,
        ReactCurrentOwner.current,
        props,
      );
    }
    
    _source 함수는 element._store.validated 세 개의 매개 변수를 받아들이고config는 createElement에 대해 특수 처리를 하며 보류된 속성을 추가 매개 변수로 전송type, config, children한다.또한 RESERVED_PROPS에 대해 ReactElement가 다중 파라미터인지 아닌지를 판단하고 여러 개children라면 수조로 부여children한다.

    cloneAndReplaceKey

    export function cloneAndReplaceKey(oldElement, newKey) {
      const newElement = ReactElement(
        oldElement.type,
        newKey,
        oldElement.ref,
        oldElement._self,
        oldElement._source,
        oldElement._owner,
        oldElement.props,
      );
    
      return newElement;
    }
    

    원래 ReactElement을 복사합니다. 키를 바꿀 뿐입니다.

    cloneElement

    /**
     * Clone and return a new ReactElement using element as the starting point.
     * See https://reactjs.org/docs/react-api.html#cloneelement
     */
    export function cloneElement(element, config, children) {
      invariant(
        !(element === null || element === undefined),
        'React.cloneElement(...): The argument must be a React element, but you passed %s.',
        element,
      );
    
      let propName;
    
      // Original props are copied
      const props = Object.assign({}, element.props);
    
      // Reserved names are extracted
      let key = element.key;
      let ref = element.ref;
      // Self is preserved since the owner is preserved.
      const self = element._self;
      // Source is preserved since cloneElement is unlikely to be targeted by a
      // transpiler, and the original source is probably a better indicator of the
      // true owner.
      const source = element._source;
    
      // Owner will be preserved, unless ref is overridden
      let owner = element._owner;
    
      if (config != null) {
        if (hasValidRef(config)) {
          // Silently steal the ref from the parent.
          ref = config.ref;
          owner = ReactCurrentOwner.current;
        }
        if (hasValidKey(config)) {
          key = '' + config.key;
        }
    
        // Remaining properties override existing 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) {
              // Resolve default props
              props[propName] = defaultProps[propName];
            } else {
              props[propName] = config[propName];
            }
          }
        }
      }
    
      // Children can be more than one argument, and those are transferred onto
      // the newly allocated props object.
      const childrenLength = arguments.length - 2;
      if (childrenLength === 1) {
        props.children = children;
      } else if (childrenLength > 1) {
        const childArray = 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);
    }
    

    create Element과 유사하지만, 다른 것은 props에 대해 얕은 합병을 하는 것이다.

    isValidElement

    /**
     * Verifies the object is a ReactElement.
     * See https://reactjs.org/docs/react-api.html#isvalidelement
     * @param {?object} object
     * @return {boolean} True if `object` is a ReactElement.
     * @final
     */
    export function isValidElement(object) {
      return (
        typeof object === 'object' &&
        object !== null &&
        object.$$typeof === REACT_ELEMENT_TYPE
      );
    }
    

    유효한 ReactElement 유형인지 판단합니다.

    좋은 웹페이지 즐겨찾기