Taiyi dev

Notes

Build your own react

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去執行優先性更高的任務。

Step IV - VIII

build-you-own-react.png

;