使用用法:
- 如何定义组件
- 函数式组件(就是一个函数,接收一个属性对象,返回一个react元素)
函数式组件渲染:
1 - 封装函数组件的属性对象 props = {name: ‘haha’}
2 - 把props传递给welcome1函数,返回一个React元素
3 - 把这个React元素,也就是虚拟DOM渲染到真实DOM
- 类组件(就是一个类,需要一个render函数,render返回返回并仅能返回一个顶级react元素)
类组件渲染:
1 - 封装函数组件的属性对象 props = {name: ‘haha’}
2 - new Welcome2(props) 创建 Welcome2 这个类的实例,传递 props 进去
3 - 调用实例的 render 方法,返回 React 元素
4 - 把这个React元素,也就是虚拟DOM渲染到真实DOM
import React from 'react';
import ReactDOM from 'react-dom';
// 函数式组件
function Welcome1 (props) {
return <h1>{props.name}</h1>
}
// 类组件
class Welcome2 extends React.Component {
render() {
return <h1>{this.props.name}</h1>
}
}
let element = <div>
<Welcome1 name="haha" />
<Welcome2 name="hehe" />
</div>
ReactDOM.render(element, document.getElementById('root'))
- props
props 具有只读性
代码如上
- PropType 类型校验
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from "prop-types"
class Welcome extends React.Component {
// 默认参数值
static defaultProps = {
name: '默认名称'
}
// 参数校验
static propTypes = {
name: PropTypes.string.isRequired, // 字符串类型的必传字段
// 自定义校验器,props 属性对象 ; propName属性名称 ; componentName 组件名称
age(props, propName, componentName) {
let age = props[propName]
if(age < 0 || age > 120) throw new Error('年龄应该在0 - 120')
}
}
render() {
return <h1>{this.props.name}</h1>
}
}
let props = {
name: '张阿三',
age: 10
}
let element = <Welcome { ...props } />
ReactDOM.render(element, document.getElementById('root'))
源码实现:
- react.js
class Component {
static isReactComponent = true
constructor(props) {
this.props = props
}
}
function createElement(type, config = {}, ...children) {
let props = {
...config,
children
}
return {
type, props
}
}
export default {
createElement,
Component
}
- react-dom.js
function render(element, container) {
if(typeof element === 'string' || typeof element === 'number') {
return container.appendChild(document.createTextNode(element))
}
let type, props;
type = element.type
props = element.props
let isReactComponent = type.isReactComponent
if(isReactComponent) {
// 类组件
let componentInstance = new type(props)
element = componentInstance.render()
type = element.type
props = element.props
} else if(typeof type === 'function') {
// 函数式组件
element = type(props)
type = element.type
props = element.props
}
let dom = createDOM(type, props)
container.appendChild(dom)
}
function createDOM(type, props) {
let dom = document.createElement(type)
for(let propName in props) {
if(propName === 'children') {
props.children.forEach(child => render(child, dom))
} else if(propName === 'className') {
dom.className = props[propName]
} else if(propName === 'style') {
let styleObj = props[propName]
for(let attr in styleObj) {
dom.style[attr] = styleObj[attr]
}
}else {
dom.setAttribute(propName, props[propName])
}
}
return dom
}
export default {
render
}
- 调用
import React from "./yuanma/react"
import ReactDOM from "./yuanma/react-dom"
// 函数组件
function Welcome(props) {
return React.createElement('h1', {
className: 'title',
id: "test",
style: {
color: 'red'
}
}, 'hello1', React.createElement('span', null, 'world1'))
}
// 类组件
class Welcome extends React.Component {
render() {
return React.createElement('h1', {
className: 'title',
id: "test",
style: {
color: 'red'
}
}, 'hello1', React.createElement('span', null, 'world12'))
}
}
let element = React.createElement(Welcome, {})
ReactDOM.render(element, document.getElementById('root'))