服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - 编程技术 - 自己造一个ReactDOM

自己造一个ReactDOM

2021-11-26 22:02魔术师卡颂卡颂 编程技术

本文会教你如何基于官方的reconciler,实现迷你ReactDOM。如果你想在任何可以绘制UI的环境使用React,都可以利用react-reconciler实现该环境下的React。

自己造一个ReactDOM

大家好,我卡颂。

React可以看作是三部分的组合:

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

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

  • scheduler的主要逻辑
  • reconciler部分逻辑
  • ReactDOM renderer的主要逻辑

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

本文参考Hello World Custom React Renderer[1]

项目初始化

通过CRA建立项目(或用已有项目):

  1. create-react-app xxx

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

  1. // 本文使用的reconciler版本是0.26.2
  2. import ReactReconciler from 'react-reconciler';
  3. const hostConfig = {};
  4. const ReactReconcilerInst = ReactReconciler(hostConfig);

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

最后,customRenderer.js导出一个包含render方法的对象:

  1. export default {
  2. render: (reactElement, domElement, callback) => {
  3. // 创建根节点
  4. if (!domElement._rootContainer) {
  5. domElement._rootContainer = ReactReconcilerInst.createContainer(domElement, false);
  6. }
  7. return ReactReconcilerInst.updateContainer(reactElement, domElement._rootContainer, null, callback);
  8. }
  9. };

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

  1. import ReactDOM from 'react-dom';
  2. import CustomRenderer from './customRenderer';
  3. // 替换ReactDOM
  4. CustomRenderer.render(
  5. ,
  6. document.getElementById('root')
  7. );

实现ReactDOM接下来我们实现hostConfig配置,首先填充空函数避免应用报错:

  1. const hostConfig = {
  2. supportsMutation: true,
  3. getRootHostContext() {},
  4. getChildHostContext() {},
  5. prepareForCommit() {},
  6. resetAfterCommit() {},
  7. shouldSetTextContent() {},
  8. createInstance() {},
  9. createTextInstance() {},
  10. appendInitialChild() {},
  11. finalizeInitialChildren() {},
  12. clearContainer() {},
  13. appendInitialChild() {},
  14. appendChild() {},
  15. appendChildToContainer() {},
  16. prepareUpdate() {},
  17. commitUpdate() {},
  18. commitTextUpdate() {},
  19. removeChild() {}
  20. }

注意这里唯一一个Boolean类型的配置项supportsMutation,他表示宿主环境的API支持mutation。

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

接下来我们来实现这些API。

实现API

这些API可以分为如下几类。

初始化环境信息

getRootHostContext与getChildHostContext用于初始化上下文信息。

生成DOM节点

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

可以将createTextInstance实现如下:

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

关键逻辑的判断

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

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

DOM操作

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

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

commitTextUpdate用于改变文本节点,实现如下:

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

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

  1. removeChild(parentInstance, child) {
  2. parentInstance.removeChild(child);
  3. }

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

自己造一个ReactDOM

完整实现的Demo地址见:完整Demo地址[2]

总结

经过本文的学习,我们实现了一个简易ReactDOM。

如果你想在任何可以绘制UI的环境使用React,都可以利用react-reconciler实现该环境下的React。

比如,Introduction To React Native Renderers[3]教你如何在Native环境实现React。

参考资料

[1]Hello World Custom React Renderer:

https://agent-hunt.medium.com/hello-world-custom-react-renderer-9a95b7cd04bc

[2]完整Demo地址:

https://codesandbox.io/s/quiet-feather-05gvk?file=/src/index.js

[3]Introduction To React Native Renderers:

https://agent-hunt.medium.com/introduction-to-react-native-renderers-aka-react-native-is-the-java-and-react-native-renderers-are-828a0022f433

原文链接:https://mp.weixin.qq.com/s/kmJWbNriGouztcGx4be8BQ

延伸 · 阅读

精彩推荐
  • 编程技术2021年值得关注的React PDF 库

    2021年值得关注的React PDF 库

    今天,许多网络应用程序为其用户提供内置的PDF浏览选项。然而,选择一个并不容易,因为它们的功能远远超过显示PDF。在这篇文章中,我将评估5个React的...

    TianTianUp5232021-06-21
  • 编程技术Delphi - Indy idMessage和idSMTP实现邮件的发送

    Delphi - Indy idMessage和idSMTP实现邮件的发送

    这篇文章主要介绍了Delphi - Indy idMessage和idSMTP实现邮件的发送,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...

    JJ_JeremyWu6592020-09-22
  • 编程技术从Context源码实现谈React性能优化

    从Context源码实现谈React性能优化

    这篇文章主要介绍Context的实现原理,源码层面掌握React组件的render时机,从而写出高性能的React组件,源码层面了解shouldComponentUpdate、React.memo、PureComponen...

    魔术师卡颂5312020-12-20
  • 编程技术AIOps,SRE工程师手中的利器

    AIOps,SRE工程师手中的利器

    AIOps开始成为一种极为重要的站点可靠性工程工具。它能够高效吸纳观察数据、参与数据以及来自第三方工具的数据,判断系统运行状态并保证其处于最佳...

    至顶网5972021-03-08
  • 编程技术真正聪明的程序员,总有办法不加班

    真正聪明的程序员,总有办法不加班

    工作效率提升了,就可以少加班了,聪明的程序员,总会有一堆可以提升编码效率的工具?当一种工具满足不了工作需求,就去探索新的,今天纬小创就给...

    今日头条12482021-03-04
  • 编程技术用户态 Tcpdump 如何实现抓到内核网络包的?

    用户态 Tcpdump 如何实现抓到内核网络包的?

    在网络包的发送和接收过程中,绝大部分的工作都是在内核态完成的。那么问题来了,我们常用的运行在用户态的程序 tcpdump 是那如何实现抓到内核态的包...

    开发内功修炼11612021-09-08
  • 编程技术简单、好懂的Svelte实现原理

    简单、好懂的Svelte实现原理

    本文会围绕一张流程图和两个Demo讲解,正确的食用方式是用电脑打开本文,跟着流程图、Demo一边看、一边敲、一边学...

    魔术师卡颂4822021-11-10
  • 编程技术让开发效率倍增的 VS Code 插件

    让开发效率倍增的 VS Code 插件

    今天来分享一些提升开发效率的实用 VS Code 插件!Better Comments 扩展可以帮助我们在代码中创建更人性化的注释,有不同形式和颜色的注释供我们选择。 ...

    前端充电宝7132022-04-21