react源码分析(2):实现一个vdom结构
2019-03-30 本文已影响0人
月肃生
前言
可以试着仿照上一节react
的用法写一个属于自己的react
- react.js
简单实现react的createElement和Component类,createElement参数(type, props,...children)基本参照原版实现
// react Component类
class Component {
constructor(props) {
this.props = props
}
render() {
}
}
// 生成一个react组件(实质上是一个对象)
function createElement(type, props, ...children){
// 参数分别是 type: 标签名或者Component对象
// props 是vdom的一些属性,像点击事件或者参数
// children 是多个参数,也是一个vdom,可以是字符串
let vdom = {
key: props && props.key,
type, // 组件类型,可以是html标签或者自己编写的react组件
props: {
...props,
ref: null, // 一个方法
}
}
// 将children也作为props的一部分
if(children.length === 1) {
vdom.props.children = children[0]
}else if(children.length > 1) {
vdom.props.children = children
}
return vdom
}
window.React = {
createElement: createElement,
Component: Component
}
- react-dom.js
针对vdom对象生成真实的dom节点
// 参数 vdom: vdom对象,node: 挂载的节点
function render(vdom, node) {
node.appendChild(renderNode(vdom))
}
// 如何根据vdom生成真实节点
function renderNode(vdom) {
const {type, props} = vdom
const children = props.children
let node
// 判断节点是不是普通html标签,没有做细致判断
if(typeof(type) === 'string') {
node = document.createElement(type) // 创建dom节点
// props暂时不处理
// 字节点处理
if(children) {
const classType = typeof(children)
if(classType === 'string') { // 判断children是不是只是一个文本,文本可以直接设置文本
node.innerText = children
}else if(children instanceof Array) { // 如果是数组,就循环递归renderNode
children.map(child => {
node.appendChild(renderNode(child))
})
}else if(children.type.prototype.__proto__ === React.Component.prototype){ // 如果是react组件就需要根据prop 初始化new 对象了
node.appendChild(renderNode(new children.type().render())) // 新建react组件需要调用render获取vdom
}
}
} else if(type.prototype.__proto__ === React.Component.prototype){ // 判断是不是react组件,初始化new 对象了
const Element = new type(props)
node = renderNode(Element.render())
}
return node
}
window.ReactDOM = {
render: render
}
- index.js
ReactDOM.render和createElement都实现,咱们可以实际使用了试试
class List extends React.Component {
render() {
return React.createElement(
"ul",
null,
React.createElement("li", null, "1"),
React.createElement("li", null, "2"),
React.createElement("li", null, "3"),
React.createElement("li", null, "4"),
);
}
}
ReactDOM.render(
React.createElement(List, null),
document.getElementById("app")
);
总结
虚拟dom的实现还是很简单的,下一节将会针对react的另一个点tree diff
算法
github地址