一、の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例を返します。