素人の言語で(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,
  });
}

复制代码

refと言うべきキー言うまでもないが、我々はすべてのGanshaある知っています。同僚が私に尋ねた前にただそこにキーを渡しReactELementコンストラクタのパラメータの核心の上に、文字列になっていた理由は、明らかにキー送信は、デジタルですkey:''+key

コードの提供、小道具やメソッドを着信defaultPropsをマージする方法後に、実際には、cloneElement方法、いくつかの同様のコードがありますが、相対的に言って、抽象化された反応しなかった、コードの冗長性があるだろうassignProps私は抽象的、時間のために抽出されています。

新しい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