前言
今天是我们建立自己的react的第三天,昨天我们讲了createElement
函数来生成虚拟dom,那么操作完dom以后,我们还要组成真实的dom,渲染到页面上,今天我们就讲渲染成真实dom,渲染到页面上。
render函数
接下来,我们要写我们的ReactDOM.render
版本。
js
ReactDOM.render(element, container)
现在,我们仅仅关心添加东西到dom里面,稍后我们将进行处理更新和删除
js
function render(element, container) {
// TODO create dom nodes
}
const Didact = {
render,
}
Didact.render(element, container)
我们开始使用element类型创造DOM节点,然后把新的节点append到container中
js
function render(element, container) {
const dom = document.createElement(element.type)
container.appendChild(dom)
}
我们递归子元素做同样的事情
js
function render(element, container) {
const dom = document.createElement(element.type)
element.props.children.forEach(child =>
render(child, dom)
)
container.appendChild(dom)
}
我们也需要处理一下文本元素,如果这个节点类型是TEXT_ELEMENT
,那么我们创建一个文本节点而不是普通节点
js
const dom =
element.type == "TEXT_ELEMENT"
? document.createTextNode("")
: document.createElement(element.type)
这里需要做的最后一件事儿是,把element的props分配给节点。
js
const isProperty = key => key !== "children"
Object.keys(element.props)
.filter(isProperty)
.forEach(name => {
dom[name] = element.props[name]
})
做到这里,现在我们有一个库可以render JSX到dom里面
js
function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children: children.map(child =>
typeof child === "object"
? child
: createTextElement(child)
),
},
}
}
function createTextElement(text) {
return {
type: "TEXT_ELEMENT",
props: {
nodeValue: text,
children: [],
},
}
}
function render(element, container) {
const dom =
element.type == "TEXT_ELEMENT"
? document.createTextNode("")
: document.createElement(element.type)
const isProperty = key => key !== "children"
Object.keys(element.props)
.filter(isProperty)
.forEach(name => {
dom[name] = element.props[name]
})
element.props.children.forEach(child =>
render(child, dom)
)
container.appendChild(dom)
}
const Didact = {
createElement,
render,
}
/** @jsx Didact.createElement */
const element = (
<div id= "foo" >
<a>bar < /a>
< b />
</div>
)
const container = document.getElementById("root")
Didact.render(element, container)