在上一篇文章的基础上添加处理类组件渲染。
1、改造index.js,实现一个类组件
// index.js
import React from './react';
import ReactDOM from './react-dom';
class Counter extends React.Component {
constructor(props) {
super(props)
this.state = { number: 0, name: this.props.name }
}
handleClick = () => {
this.setState({
number: this.state.number + 1
})
}
render() {
return (
<div>
{this.state.name}
<div>{this.state.number}</div>
<button onClick={this.handleClick}>增加</button>
</div>
)
}
}
ReactDOM.render(<Counter name="计算器" />, document.getElementById('root'));
2、实现类组件继承的Component父类
// Component.js
import { createDom } from './react-dom'
class Component {
static isReactComponent = true // 标记类组件
constructor(props) {
this.props = props
this.state = {}
}
render() {
throw new Error("此方法为抽象方法,需要子类实现")
}
}
export default Component
3、将Component放在react对象上
// react.js
import Component from "./Component";
const React = { createElement, Component }
4、类组件挂载逻辑处理
4.1 根据类组件标记判断是否为类组件
4.2 mountClassComponent方法处理
/**
* 挂载类组件
* @param {*} vdom 类组件虚拟dom
*/
function mountClassComponent(vdom) {
const { type, props } = vdom
// 创建类的实例
const classInstance = new type(props)
// 调用render方法,返回要渲染的虚拟dom对象
const renderVdom = classInstance.render()
// 根据虚拟dom创建真实dom对象
const dom = createDom(renderVdom)
// 为以后类组件更新做准备,把真实dom挂载到实例上
classInstance.dom = dom
return dom
}
5、类组件更新逻辑处理
5.1 更新方法setState实现
// Component.js
setState(partialState) {
const state = this.state
// 新的state和旧的state合并
this.state = { ...state, ...partialState };
const newVdom = this.render()
updateClassComponent(this, newVdom)
}
function updateClassComponent(classInstance, newVdom) {
const oldDom = classInstance.dom // 取出类组件上次渲染出来的真实dom
// 创建新的DOM
const newDom = createDom(newVdom)
// 新的替换老的
oldDom.parentNode.replaceChild(newDom, oldDom)
classInstance.dom = newDom
}
5.2 更新新的dom
react-dom.js文件updateProps方法增加对属性方法的判断
6、实现效果
7、源代码
本文地址:https://gitee.com/linhexs/react-write/tree/3.react-ClassComponent-render/