1227 文字
6 分
React ソースコード入門 - ReactElement
ReactElement
このモジュールはReact要素の振る舞いとメソッドを定義しています。まず、ReactElement
関数を見てみましょう。
ReactElement
var ReactElement = function (type, key, ref, self, source, owner, props) {
var element = {
// This tag allow 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;
};
DEV
内の内容を除けば、他の部分は非常にシンプルで、React要素が持つべき属性を定義しています。これには、type
, key
, ref
, self
, source
, owner
, props
が含まれます。
また、$$typeof
属性という定数があり、これはそのオブジェクトがReact要素であるかどうかを判断するために使用されます。
var REACT_ELEMENT_TYPE =
(typeof Symbol === "function" && Symbol.for && Symbol.for("react.element")) ||
0xeac7;
ReactElement.createElement
ReactElement.createElement = function (type, config, children) {
var propName;
// Reserved names are extracted
var props = {};
var key = null;
var ref = null;
var self = null;
var source = null;
if (config != null) {
// ref 和 key 都属于保留 props key 值,所以这里需要做判断
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = "" + config.key;
}
// __self 和 __source 这两个属性目前没有看到他们的作用,先放着
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// Remaining properties are added to a new props object
// 其他的属性添加到新的 props 对象上,同时需要排除掉保留字段 RESERVED_PROPS
// var RESERVED_PROPS = {key: true, ref: true, __self: true, __source: true,};
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
// Children 可以传递一个以上的参数,这些 children 参数都会作为新分配的 props 的属性
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 (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}
// 设置 defaultProps 属性
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
// 开发环境下,如果使用了保留字段 key 和 ref ,那么进行控制台报错提醒
if (__DEV__) {
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);
}
}
}
}
// 返回一个 React 元素, ReactCurrentOwner.current 是指当前正处于构建过程中的组件,这里默认是 null
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
};
与えられた引数を使ってReact要素を作成します。ref
とkey
は予約済みフィールドであり、props
の属性として渡すことはできない点に注意が必要です。
ReactElement.createFactory
同じ型のコンポーネントを簡単に作成するためのシンプルなファクトリ関数です。
ReactElement.createFactory = function (type) {
var factory = ReactElement.createElement.bind(null, type);
// Expose the type on the factory and the prototype so that it can be
// easily accessed on elements. E.g. `<Foo />.type === Foo`.
// This should not be named `constructor` since this may not be the function
// that created the element, and it may not even be a constructor.
// Legacy hook TODO: Warn if this is accessed
factory.type = type;
return factory;
};
ReactElement.cloneAndReplaceKey
このAPIは使用したことがありませんが、React要素の予約済み属性であるkey
値を置き換えるために使用できます。
ReactElement.cloneAndReplaceKey = function (oldElement, newKey) {
var newElement = ReactElement(
oldElement.type,
newKey,
oldElement.ref,
oldElement._self,
oldElement._source,
oldElement._owner,
oldElement.props,
);
return newElement;
};
ReactElement.cloneElement
cloneElement
メソッドはcreateElement
と基本的に同じですが、前者は既存のReact要素から新しい要素を複製するという点が異なります。
ReactElement.isValidElement
オブジェクトが有効なReact要素であるかどうかを判断するために使用されます。
ReactElement.isValidElement = function (object) {
return (
typeof object === "object" &&
object !== null &&
object.$typeof === REACT_ELEMENT_TYPE
);
};
上で最初に定義した$$typeof
属性が使われています。
export
module.exports = ReactElement;
ReactElement
モジュールはこれらで構成されており、主にReact要素が持つべき属性と、要素を操作するためのいくつかのメソッドを定義しています。
関連記事
- {% post_link react-source-code-analyze-1 Reactソースコードの深掘り - エントリファイル編 %}
- {% post_link react-source-code-analyze-2 Reactソースコードの深掘り - ReactBaseClasses編 %}
- {% post_link react-source-code-analyze-3 Reactソースコードの深掘り - ReactChildren編 %}
- {% post_link react-source-code-analyze-4 Reactソースコードの深掘り - ReactElement編 %}
- {% post_link react-source-code-analyze-5 Reactソースコードの深掘り - onlyChildren編 %}
この記事は 2017年9月21日 に公開され、2017年9月21日 に最終更新されました。2937 日が経過しており、内容が古くなっている可能性があります。
React ソースコード入門 - ReactElement
https://blog.kisnows.com/ja-JP/2017/09/21/react-source-code-analyze-4/