평신도의 언어 (2)의 createElement와 ReactElement을 구문 분석의 핵심 소스 코드 반응

一, createElement와

우리가 이야기의 마지막 장에 대한 모든 jsx 문법의 createElement로 변환됩니다.

다음의 createElement의 실현은 무엇입니까?

첫째, 우리는 소스 라이브러리를 반응 GitHub의에서 복제, 우리는 먼저 소스 라이브러리 반응에 따라 파일의 레이아웃을 분석 할 수 있습니다.

프로젝트 루트 폴더 패키지에서이 반응, 각 패킷 사이에 위치는 우리가 디렉토리 반응 초점에 넣어 가지고 반응한다. 내부는 소스 코드 구현을 반응이다.

감지하고 코드를 경고 던져 일부 중요하지 않은는 코어는 사실 코드의 단지 몇 백 라인을 반응한다. 반응-DOM 가장 복잡한 렌더링에 대한 책임 자체는 복잡하지 소스를 반응한다.

SRC는 디렉토리 달성 반응의 핵심입니다 반응한다.

다음의 createElement 방법은 구현 ReactElement.js 파일에 있습니다 :


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


复制代码

그리고이 개발 환경에서 몇 가지 테스트가 있으며, 외부 호출 방법은, 독자가 산만하게 동일한 기능, 그리고 더 나은 독서를 만들기 위해 코드를 간소화하기 위해 약간의 변화를 실망 할 수있다 :

export function createElement(type, config, ...children) {
  const {ref = null, key = null} = config || {};
  const {current} = ReactCurrentOwner;
  const {defaultProps} = type || {};
  const props = assignProps(config, defaultProps, children);

  return new ReactElement({
    type,
    key: '' + key,
    ref,
    current,
    props,
  });
}
复制代码

후 간소화하고, 코드의 createElement와 30 라인을 단순화합니다. 우리는 라인별로 다음 행을 결심했다.

/**
 * 
 * @param type {string | function | object}  
 *        如果type是字符串,那就是原生dom元素,比如div
 *        如果是function或者是Component的子类 则是React组件
 *        object 会是一些特殊的type 比如fragment
 * @param config {object}
 *        props 和key 还有ref 其实都是在config里了
 * @param children
 *        就是由其他嵌套createElement方法返回的ReactElement实例
 * @returns {ReactElement}
 * 
 */
export function createElement(type, config, ...children) {
    
  // 给config设置一个空对象的默认值
  // ref和key 默认为null
  const {ref = null, key = null} = config || {};
  // ReactCurrentOwner负责管理当前渲染的组件和节点
  const {current} = ReactCurrentOwner;
  // 如果是函数组件和类组件 是可以有defaultProps的
  // 比如
  // function A({age}) {return <div>{age}</div>}
  // A.defaultProps = { age:123 }
  const {defaultProps} = type || {};
  // 把defaultProps和props 合并一下
  const props = assignProps(config, defaultProps, children);
  // 返回了一个ReactElement实例
  return new ReactElement({
    type,
    key: '' + key,
    ref,
    current,
    props,
  });
}

复制代码

심판 및 키없이 우리 모두가 Gansha 알고, 말할 수 있습니다. 동료가 나에게 물었다 전에 그냥 키를 전달 ReactELement 생성자 매개 변수의 핵심 위 문자열이되었다 이유를 분명히 키 전송은 디지털입니다 key:''+key.

, defaultProps 들어오는 소품과 방법을 병합 나중에 코드를 제공 할 수있는 방법 assignProps I 추상적 인은, 사실, cloneElement 방법은 몇 가지 유사한 코드가 있지만, 상대적으로 말하기, 추상화 된 반응하지 않은 코드 중복이있을 것이다 시간 추출된다.

새로운 ReactElement에 초점 ().

코드를 반응 개체를 반환하는 공장 기능을 ReactElement. 그러나 나는 개인적으로 오히려 이상한 생각합니다.

첫째, 공장 함수 인스턴스는, 공장은 자본 기능을 시작해야한다.

둘째, ReactElement이 더 나은, 더 일관성있는 선택의 의미가 없습니다 선언 생성자 또는 클래스를 사용?

여기에, 이해의 용이성, 기능 ReactElement 공장의 예는, 클래스에서 다양 한의 createElement와 ReactElement 클래스로의 회귀이다.

여기 asssignProps 달성 보면, 방법은 cloneElement 다중화 될 수있다 :


const RESERVED_PROPS = ['key', 'ref', '__self', '__source'];

export function assignProps(config, defaultProps, children) {
  
    const props = {
        children,
    };
    config = config || {};
    for (const propName in config) {
        if (
            config.hasOwnProperty(propName) &&
            !RESERVED_PROPS.includes(propName)
        ) {
            props[propName] = config[propName];
            if (
                props[propName] === undefined &&
                defaultProps &&
                defaultProps[propName] !== undefined
            ) {
                props[propName] = defaultProps[propName];
            }
        }
    }

    return props;
}


复制代码

二, ReactElement

반환에게 ReactElement 인스턴스를 만든 다음 ReactElement는 셰인은?

간소화 된 후 다음과 같이 dev에 던져 코드 :


const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    $$typeof: REACT_ELEMENT_TYPE,
    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner,
  };

  return element;
};


复制代码

당신은 우리가 간단하고 장대 한 상상력에서 지금, 사실, 개체를 반환 볼 수, 메커니즘 기본 DOM의 방법에 따라 만든 레이어 렌더링, 실제로 이러한 데이터 구조 및 트리의 구조를 읽어 반응 렌더링합니다. (일시적으로 그렇게 상상)

클래스의 코드 변환 후 :


export class ReactElement {
  constructor(elementParams) {
    const {type, key, ref, current, props} = elementParams || {};
    // 如果是原生标签比如h1 那就是字符串
    // 如果是组件 则是组件的引用
    this.type = type;
    // key
    this.key = key;
    // ref
    this.ref = ref;
    // 延后再讲
    this._owner = current;
    // props
    this.props = props;
    // 类型标识 新版本中的React里是symbo
    this.$$typeof = REACT_ELEMENT_TYPE;
  }
}

复制代码

셋째, 요약

장이 집중에 반응하고, 라벨의 성격 jsx ReactElement, createElement와의 DOM 것입니다 구성 요소 또는 캡슐 형태의 계층을 통해, 그리고 소품, 그리고 마지막으로 ReactElement 예를 반환합니다.

추천

출처blog.csdn.net/weixin_33966095/article/details/91375208