持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情
1. 面试题:jsx是什么,是html吗?
首先jsx不是html 只是以类似html的形式来定义页面, 实际是根据写的jsx生成Virtual Dom , 然后再根据virtual dom来用js中的dom相关api生成实际页面
<div className="container">
<div>Hello React</div>
<p>React is great </p>
</div>
2. Virtual-Dom 是什么
virtual dom实际就是jsx转换为用key value形式来描述jsx的对象
上面的jsx对应的dom会转化为下面的形式
{
type: "div",
props: { className: "container" },
children: [
{
type: "div",
props: null,
children: [
{
type: "text",
props: {
textContent: "Hello React"
}
}
]
},
{
type: "p",
props: null,
children: [
{
type: "text",
props: {
textContent: "React is great"
}
}
]
}
]
}
没错上面的对象就是虚拟dom
为什么虚拟dom能够提高效率
虚拟dom如何工作的呢 实际开发过程中频繁操作dom是最耗性能的。 实际上正式由于虚拟dom操作的便利性 我们可以对比数据是否变化,有变化, 对变化的部分的dom做对应的增删改查操作。 没变化就不会更新
before
<div className="container">
<div>123</div>
</div>
after
<div className="container">
<div>123</div>
</div>
对应虚拟dom
{
type: "div",
props: { className: "container" },
children: [
{
type: "div",
props: null,
children: [
{
type: "text",
props: {
① textContent: "123"
}
}
]
}
]
}
实际变化的就是①处的123变成了456
Virtual-Dom 如何工作
创建Virtual-Dom
babel会将jsx转化为React.createElement()形式的代码
而createElement方法则会返回对应的虚拟dom
export default function createElement(type, props, ...children) {
const childElements = [].concat(...children).reduce((result, child) => {
if (child !== false && child !== true && child !== null) {
if (child instanceof Object) {
result.push(child)
} else {
result.push(createElement("text", { textContent: child }))
}
}
return result
}, [])
return {
type,
props: Object.assign({ children: childElements }, props),
children: childElements
}
}
生成对应的页面
// render.js
import mountNativeElement from "./mountNativeElement"
export default function render(
virtualDOM,
container,
oldDOM = container.firstChild
) {
mountNativeElement(virtualDOM, container)
}
// mountNativeElement.js
import createDOMElement from "./createDOMElement"
export default function mountNativeElement(virtualDOM, container) {
const newElement = createDOMElement(virtualDOM)
container.appendChild(newElement) // 生成的dom实例添加到container上
}
// createDOMElement.js
import mountElement from "./mountElement"
import updateElementNode from "./updateElementNode"
export default function createDOMElement(virtualDOM) {
let newElement = null
// 创建文本节点
if (virtualDOM.type === "text") {
newElement = document.createTextNode(virtualDOM.props.textContent)
} else {// 创建元素节点
newElement = document.createElement(virtualDOM.type)
// 更新元素属性
updateElementNode(newElement, virtualDOM)
}
// 递归渲染子节点
virtualDOM.children.forEach(child => {
// 因为不确定子元素是 NativeElement 还是 Component 所以调用 mountElement 方法进行确定
mountElement(child, newElement)
})
return newElement
}
调用
TinyReact.render(<KeyDemo />, root)
以上便是完整的生成和渲染过程。