手写react二

83 阅读2分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。

实现

我们将分为8步,一步一步的实现一个小型的React

  • 实现createElement函数
  • 实现render函数
  • Currnet Mode模式
  • fibers
  • render和commit阶段
  • 协调器
  • function组件
  • hooks

实现render函数

接下来我们来实现ReactDOM.render函数,继续使用笔记一的代码,新增render函数

const Didect = {
    createElement,
    render,
}
function render(element, container) {
    // TODO create dom nodes
}
const element = (
    <div id="foo">
        <a>bar</a>
        <b />
    </div>
)
const container = document.getElementById("root") 
Didect.render(element, container)

我们先根据元素的类型创建新dom节点,然后将新dom节点加入到container中,然后递归的创建子dom节点

function render(element, container) {
    const dom = document.createElement(element.type);
    element.props.children.forEach(child => render(child, dom))
    container.appendChild(dom)
}

这里我们还需要处理text元素,如果元素的type为TEXT_ELEMENT,需要创建一个text节点

function render(element, container) {
    const dom =
        element.type == "TEXT_ELEMENT"
        ? document.createTextNode("")
        : document.createElement(element.type)
    element.props.children.forEach(child => render(child, dom))
    container.appendChild(dom)
}

最后我们需要将属性加到dom节点上,也就是props对象里除了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]
        })
    container.appendChild(dom)
}

到目前为止我们已经完成了一个简单的render函数啦,现在可以将JSX渲染为dom元素了。

总结

目前实现的render函数采用的是递归的方式创建dom节点,也是react15使用的方式。浏览器普遍的刷新率是60fps,也就是60帧每秒。也就是在16.6ms内js还没执行完,就会出现卡顿。它的主要问题是,当dom节点达到一个量级时,render递归地创建dom节点且不可中断,一直占用着线程,从而会导致页面出现卡顿的情况。

所以react会进行重构,react16实现了全新架构,主要实现了可中断异步更新。下一章我们会对render进行重构,实现可中断更新。