一:组件是什么
先看一下我们经常写的组件
import React from 'react'
import ReactDOM from 'react-dom';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'Dan'
};
}
componentDidMount() {
}
doSomething = () => {
this.setState({
name: 'Big Dan'
})
}
render() {
const { name } = this.state;
return (
<div>
<span>
{name}
</span>
</div>
)
}
}
console.log(<App />);
ReactDOM.render(<App />, document.getElementById('root'));
再看一下最终babel编译后的结果
"use strict";
var _createClass = (function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
})();
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _reactDom = require("react-dom");
var _reactDom2 = _interopRequireDefault(_reactDom);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError(
"this hasn't been initialised - super() hasn't been called"
);
}
return call && (typeof call === "object" || typeof call === "function")
? call
: self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError(
"Super expression must either be null or a function, not " +
typeof superClass
);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass)
Object.setPrototypeOf
? Object.setPrototypeOf(subClass, superClass)
: (subClass.__proto__ = superClass);
}
var App = (function(_React$Component) {
_inherits(App, _React$Component);
function App(props) {
_classCallCheck(this, App);
var _this = _possibleConstructorReturn(
this,
(App.__proto__ || Object.getPrototypeOf(App)).call(this, props)
);
_this.doSomething = function() {
_this.setState({
name: "Big Dan"
});
};
_this.state = {
name: "Dan"
};
return _this;
}
_createClass(App, [
{
key: "componentDidMount",
value: function componentDidMount() {}
},
{
key: "render",
value: function render() {
var name = this.state.name;
return _react2.default.createElement(
"div",
null,
_react2.default.createElement("span", null, name)
);
}
}
]);
return App;
})(_react2.default.Component);
console.log(_react2.default.createElement(App, null));
ReactDom.render(
_react2.default.createElement(App, { name: "a" }, "hello"),
document.querySelector("body")
);
可以看到我们最终写的组件都会放在react.createElement中,那createElement究竟干了什么呢?我们来看一下createElement方法的实现源码
// 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) {
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.
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 (process.env.NODE_ENV !== 'production') {
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}
// Resolve default props
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
if (process.env.NODE_ENV !== 'production') {
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);
}
}
}
}
return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
};
// createElement调用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 (process.env.NODE_ENV !== 'production') {
// 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.
if (canDefineProperty) {
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
});
} else {
element._store.validated = false;
element._self = self;
element._source = source;
}
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}
return element;
};
大家可以看到createElement做了这么几件事儿:
- 把config中的key、ref作为element的key、ref
- 把config中自己的属性放到element的props上,把组件类的defaultProps放到element的props上,把孩子元素放到elementd的props中的children上
- 把组件的类放到element的type上 所以大家可以看到上边的代码打印出的实际就是element对象
