【mini-react系列】一、createElement和render函数

374 阅读3分钟

前言

最近参加了 崔效瑞老师 的7天mini-react训练营,虽然每天工作很忙,但还是抽出一两个小时跟进学习,坚持了7天,还是得给坚持到最后的自己点个赞!

虽然之前没有接触过React的源码,但是通过学习任务的拆分,将复杂模块的任务拆分成一个个小任务,小步走实现,再逐步优化代码。

时间虽短,内容却不少。先开始浅浅地记录下我的学习成果,先起个好头,希望今年能顺利更新完这个系列,给2024的自己先立第一个flag!!

在这7天的mini-react训练营中,我学到了:

  • 实现createElementrender函数
  • 实现任务调度器requestIdleCallback
  • 实现简易的fiber
  • 实现functionComponent
  • 实现事件绑定
  • 实现props
  • 实现diff更新
  • 实现useState
  • 实现useEffect

话不多说,进入今天的主题,先开始React的初始化,实现createElementrender函数

createElement函数

createElement 函数是用于创建虚拟 DOM 元素的函数。它通常被 JSX 编译器所使用,用来将 JSX 语法转换为对 React.createElement 的调用。

function createTextNode(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: [],
    },
  }
}

function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map((child) => {
        const isTextNode = typeof child === "string" || typeof child === "number"
        return isTextNode ? createTextNode(child) : child
      }),
    },
  }
}

createElement 函数接受三个参数:type 表示元素的类型(例如 'div'),props 表示元素的属性(例如 { className: 'my-class' }),以及 children 表示元素的子元素。在实现中,它返回一个包含 typeprops 属性的对象。

为了处理文本节点,我们还定义了 createTextNode 函数,它创建一个特殊的类型为 'TEXT_ELEMENT' 的对象,用于表示文本节点。

在实际使用中,React 会递归地处理这些虚拟 DOM 对象,最终将它们转换为实际的 DOM 元素并渲染到页面上。

注意: 上述代码只是一个简化版的实现,真实的 React 源码中应该更加复杂,并包含更多的功能和优化。

render函数

render 函数是 React 中用于将虚拟 DOM 渲染到实际 DOM 的核心函数。

function render(el, container) {
  const dom = el.type === "TEXT_ELEMENT"
    ? document.createTextNode("")
    : document.createElement(el.type)

  // id class
  Object.keys(el.props).forEach((key) => {
    if (key !== "children") {
      dom[key] = el.props[key]
    }
  })
  const children = el.props.children
  children.forEach((child) => {
    render(child, dom)
  })
  container.append(dom)
}

render 函数接受两个参数:element 表示要渲染的虚拟 DOM 元素,container 表示要渲染到的实际 DOM 容器。
首先,根据虚拟 DOM 的类型创建对应的实际 DOM 元素(文本节点和普通元素分别处理)。然后,将虚拟 DOM 元素的属性设置到实际 DOM 元素上,遍历子元素并递归调用 render 函数。最后,将创建好的实际 DOM 元素添加到容器中。

导出render函数

ReactDom文件导出render函数之后, 调用ReactDOM.createRoot(element).render 函数。这样,就可以使用 React 的渲染功能了。

import React from "./React.js"
const ReactDOM = {
  createRoot(container) {
    return {
      render(App) {
        React.render(App, container)
      },
    }
  },
}

export default ReactDOM

示例解析

简单的渲染代码

function App() {
  return (
    <div>
      hello world, my mini react!
      <div>befend</div>
    </div>
  )
}

export default App;

节点创建的过程内容

image.png

渲染结果

image.png

小结

  • createElement 和 render 是 React 中用于构建和渲染界面的核心函数。
  • 通常,createElement 函数用于创建虚拟 DOM 元素,通常由 JSX 编译器转换 JSX 语法时调用。而 render 函数将虚拟 DOM 渲染到实际 DOM。

总的来说,createElement 用于创建虚拟 DOM 元素,而 render 用于将这些虚拟 DOM 元素渲染到实际 DOM 中,从而构建用户界面。

仓库传送门: github.com/Befend/mini…