Source
使用Vite建立一個環境測試
pnpm create vite
# build-your-own-react
# vanillaJS
Step 0
main.js
const element = {
type: "h1",
props: {
title: "foo",
children: "Hello1"
}
}
const node = document.createElement(element.type)
node["title"] = element.props.title
const text = document.createTextNode("")
text["nodeValue"] = element.props.children
node.appendChild(text)
const container = document.getElementById('app')
container.appendChild(node)
Step I: createElement()
Step II: render()
my-react.js
const TEXT_ELEMENT = "TEXT ELEMENT";
const createElement = (type, props, ...children) => {
return {
type,
props: {
...props,
children: children.map(child => typeof child === "object"
? child : createTextElement(children)
)
}
}
}
const createTextElement = text => ({
type: TEXT_ELEMENT,
props: {
nodeValue: text,
children: []
}
})
const render = (element, container) => {
const dom =
element.type == TEXT_ELEMENT
? document.createTextNode("")
: document.createElement(element.type)
Object.keys(element.props)
.filter(key => key !== "children")
.forEach(name => {
dom[name] = element.props[name]
})
element.props.children.forEach(child =>
render(child, dom)
)
container.appendChild(dom)
}
const MyReact = {
createElement,
render
}
export default MyReact
main.jsx
import MyReact from './my-react'
/* @jsx MyReact.createElement */
const element = (
<div style="background: salmon">
<h1>Hello World</h1>
<h2 style="text-align:right">from Didact</h2>
</div>
)
const container = document.getElementById('app')
MyReact.render(element, container)
為什麼加上註解 /* @jsx MyReact.createElement */
就可以將jsx轉換成vdom?
這種註解稱為jsx pragma, 讓transpiler知道每個jsx需要執行MyReact.createElement
參考: WTF is JSX
Step III: Concurrent Mode
const performUnitOfWork = (nextUnitOfWork) => {
console.log("performUnitOfWord...");
};
let nextUnitOfWork = null;
const workLoop = (deadline) => {
let shouldYield = false;
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
shouldYield = deadline.timeRemaining() < 1;
};
requestIdleCallback(workLoop);
之前的render()
沒辦法中斷,tree很大時會卡住call stack,無法停止render去執行優先性更高的任務。
- requestIdleCallback - MDN
- Similar to
setTimeout
,but the difference is the function will be called during a browser's idle periods.
- Similar to