继承React.component
自定义的组件要继承React.compoent,自定义的类中必须要实现一个render方法。
class Clock extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props}.</h2>
</div>
);
}
}
通过super(props)将自定义组件的props绑定到了实例对象上,不需要重复书写this.props = props,在render函数中可以直接使用this.props。因为react.component内部的实现如下
function Component(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
this.updater = updater || ReactNoopUpdateQueue;
}
render函数中的JSX-react.createElement
render函数中的JSX(HTML)代码会被@babel/plugin-transform-react-jsx这个babel转译插件转换为React.creactElement
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
</div>
);
}
}
等效于
class Clock extends React.Component {
render() {
return (
React.createElement(
'div',
{
title: 'aa',
},
React.createElement('h1', {}, 'Hello, world!')
)
);
}
}
所以出现了JSX语法的模块一定要引入react。
react.createElement的作用是返回一个虚拟dom,大致的代码如下。
function createElement(type, attributes, ...children) {
let e
if (typeof type == 'string') {
e = new ElementWrapper(type)
} else {
e = new type()
}
for (let p in attributes) {
e.setAttribute(p, attributes[p])
}
let insertChildren = (children) => {
for (let child of children) {
if (typeof child === 'string') {
child = new TextWrapper(child)
}
if (typeof child === 'object' && child instanceof Array) {
insertChildren(child)
} else {
e.appendChild(child)
}
}
}
insertChildren(children)
return e
}
e就是一个虚拟dom。
- 如果是一个原生的dom节点会调用
new ElementWrapper(type) - 如果是自定义的组件会调用
new type(),最后还是转化为new ElementWrapper(type)ElementWrapper的实现如下
class ElementWrapper {
constructor(type) {
this.root = document.createElement(type)
}
setAttribute(name, value) {
this.root.setAttribute(name, value)
}
appendChild(component) {
this.root.appendChild(component.root)
}
}