从零实现一个mini-react(一)createElement和render

315 阅读1分钟

话不多说,直接开始

create-react-app生成项目

终端创建,使用命令如下

yarn create-react-app micro-react --template typescript

src文件中 只剩下 index.ts 新创建文件夹 react 和 react-dom

类似

就是我们的初始文件

代码地址☝️ github.com/beewolf233/…

react最基本思想

就是将虚拟DOM 转为 真实DOM

createElement

创建虚拟DOM, 在react/index.ts下 创建createTextElement 函数 用来 生成虚拟DOM

import type { VDOMProps } from '../shared';

/**
 * @param type 便签类型
 * @param props 属性
 * @param children 孩子
 * */ 
export function createElement(type: VDOMProps['type'], props: VDOMProps, ...children: VDOMProps['props']['children']) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === "object"
        ? child
        : createTextElement(child)
                            ),
    },
  }
}

function createTextElement(text: string | number): VDOMProps {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: [],
    },
  }
}

const React = {
  createElement,
}

export default React;

render

渲染虚拟DOM变为真实DOM, 在 react-dom/index.ts下

import type { VDOMProps } from '../shared';

function render(vDom: VDOMProps , container:  HTMLElement | Text) {
  const dom =
    vDom.type === "TEXT_ELEMENT"
      ? document.createTextNode("")
      : document.createElement(vDom.type)

  const isProperty = (key: string) => key !== "children"

  Object.keys(vDom.props)
    .filter(isProperty)
    .forEach(name => {
      // css属性
      if (name === 'style') {
        let styleObj = vDom.props[name];
        for (let attr in styleObj) {
           // @ts-ignore 
          (dom as HTMLElement).style[attr] = styleObj[attr];
        }
        return
      }
      // @ts-ignore
      dom[name] = vDom.props[name]
    })

  const children = vDom.props.children;

  children.forEach(child =>
    render(child, dom)
  )

  container.appendChild(dom)
}

const ReactDOM = {
  render
}

export default ReactDOM;

在 src/index页面进行 创建虚拟DOM 进行渲染,

注意⚠️: 必须通过 /** @jsxRuntime classic */ 才能渲染 自定义的createElement 函数渲染格式

import React from './react';
import ReactDOM from './react-dom';

/** @jsxRuntime classic */
const element = (
  <div style={{background: 'salmon'}}>
    <h1>Hello World</h1>
    <h2 style={{textAlign: 'right' }}>from Didact</h2>
  </div>
);


const container = document.getElementById("root") as HTMLElement;
ReactDOM.render(element, container);

以上就实现了 最基础的 react模型

代码地址 github.com/beewolf233/…

参考文章

juejin.cn/post/702331…

juejin.cn/post/720811…

pomb.us/build-your-…

下一节  改善render性能 引入 fiber结构 和协调器概念