关于javascript:自己造一个ReactDOM

38次阅读

共计 2504 个字符,预计需要花费 7 分钟才能阅读完成。

大家好,我卡颂。

React能够看作是三局部的组合:

  • scheduler,调度器,用于调度工作
  • reconciler,协调器,用于计算工作造成的副作用
  • renderer,渲染器,用于在宿主环境执行副作用

这三者都是独立的包,咱们我的项目里引入的 ReactDOM 能够看作是以下三局部代码打包而成:

  • scheduler的次要逻辑
  • reconciler局部逻辑
  • ReactDOM renderer的次要逻辑

本文会教你如何基于官网的reconciler,实现迷你ReactDOM

本文参考 Hello World Custom React Renderer

我的项目初始化

通过 CRA 建设我的项目(或用已有我的项目):

create-react-app xxx

新建 customRenderer.js,引入react-reconciler 并实现初始化:

// 本文应用的 reconciler 版本是 0.26.2
import ReactReconciler from 'react-reconciler';

const hostConfig = {};
const ReactReconcilerInst = ReactReconciler(hostConfig);

其中 hostConfig 就是宿主环境的配置项。

最初,customRenderer.js导出一个蕴含 render 办法的对象:

export default {render: (reactElement, domElement, callback) => {
    // 创立根节点
    if (!domElement._rootContainer) {domElement._rootContainer = ReactReconcilerInst.createContainer(domElement, false);
    }

    return ReactReconcilerInst.updateContainer(reactElement, domElement._rootContainer, null, callback);
  }
};

在我的项目入口文件,将 ReactDOM 换成咱们实现的CustomRenderer

import ReactDOM from 'react-dom';
import CustomRenderer from './customRenderer';

// 替换 ReactDOM
CustomRenderer.render(
  <App />,
  document.getElementById('root')
);

实现 ReactDOM

接下来咱们实现 hostConfig 配置,首先填充空函数防止利用报错:

const hostConfig = {
  supportsMutation: true,
  getRootHostContext() {},
  getChildHostContext() {},
  prepareForCommit() {},
  resetAfterCommit() {},
  shouldSetTextContent() {},
  createInstance() {},
  createTextInstance() {},
  appendInitialChild() {},
  finalizeInitialChildren() {},
  clearContainer() {},
  appendInitialChild() {},
  appendChild() {},
  appendChildToContainer() {},
  prepareUpdate() {},
  commitUpdate() {},
  commitTextUpdate() {},
  removeChild() {}
}

留神这里惟一一个 Boolean 类型的配置项 supportsMutation,他示意宿主环境的API 反对mutation

这是 DOM API 的工作形式,比方 element.appendChildelement.removeChild。如果是Native 环境则不是这种工作形式。

接下来咱们来实现这些API

实现 API

这些 API 能够分为如下几类。

初始化环境信息

getRootHostContextgetChildHostContext 用于初始化上下文信息。

生成 DOM 节点

  • createInstance用于创立 DOM 节点
  • createTextInstance用于创立文本节点

能够将 createTextInstance 实现如下:

createTextInstance: (text) => {return document.createTextNode(text);
}

要害逻辑的判断

shouldSetTextContent用于判断组件的 children 是否是 文本节点,实现如下:

shouldSetTextContent: (_, props) => {return typeof props.children === 'string' || typeof props.children === 'number';},

DOM 操作

appendInitialChild用于插入 DOM 节点,实现如下:

appendInitialChild: (parent, child) => {parent.appendChild(child);
},

commitTextUpdate用于扭转 文本节点,实现如下:

commitTextUpdate(textInstance, oldText, newText) {textInstance.text = newText;},

removeChild用于删除子节点,实现如下:

removeChild(parentInstance, child) {parentInstance.removeChild(child);
}

当实现了所有 API 后,页面就能失常渲染了:

残缺实现的 Demo 地址见:残缺 Demo 地址

总结

通过本文的学习,咱们实现了一个繁难ReactDOM

如果你想在任何能够绘制 UI 的环境应用 React,都能够利用react-reconciler 实现该环境下的React

比方,Introduction To React Native Renderers 教你如何在 Native 环境实现React

欢送退出人类高质量前端框架群,带飞

正文完
 0