发布于 2026-01-05 0 阅读
0

用 90 行 JavaScript 代码构建你自己的 React 系统 快速简易 React 教程 🔨

用 90 行 JavaScript 代码构建你自己的 React 系统

快速简易 React 🔨

我无法创造的事物,我就无法理解——理查德·费曼

当我开始学习 React 时,感觉它简直神奇无比。后来我开始思考,这神奇的原理究竟是什么。当我意识到 React 的功能其实非常简单,即使我们并非把它寄托于下一个大型创业项目,也能用几行 JavaScript 代码轻松实现时,我简直惊呆了。正是这种感受促使我写下这篇文章,希望读完之后,你也能有同样的感受。

我们将开发哪些功能?

JSX

这一点显而易见,因为我们正在构建一个 React 克隆项目。我们还会添加事件绑定功能。

功能组件

我们还将支持带有 props 的功能组件。

具有状态的类组件

我们将通过 props 和 state 来支持 Class 组件,以便更新我们的组件。

生命周期钩子

为了简单起见,我们只实现 componentDidMount() 生命周期钩子。

我们不会建造什么?

虚拟 DOM

是的,为了简单起见,我们至少在本文中不会自己实现虚拟 DOM,而是使用现成的虚拟 DOM——snabbdom。有趣的是,Vue.js 也使用了 snabbdom。您可以在这里了解更多信息。

GitHub 标志 snabbdom / snabbdom

一个注重简洁性、模块化、强大功能和高性能的虚拟 DOM 库。

React Hooks

有些人读到这里可能会感到失望,但我们不想好高骛远,所以先从基础做起,以后再逐步添加其他功能。我还计划撰写专门的文章,讲解如何在现有基础上实现我们自己的 React Hooks 和虚拟 DOM。

可调试性

这是任何库或框架增加复杂性的关键部分之一,由于我们只是为了好玩而这样做,我们可以忽略 React 提供的调试功能,例如开发者工具和分析器。

性能和便携性

我们不会太在意库的效率或速度有多快,我们只想做出一个能用的东西。我们也不必费尽心思去确保它能兼容市面上所有的浏览器,只要能兼容几款主流浏览器就足够了。

让我们亲自动手吧。

猫电脑

在开始之前,我们需要一个支持 ES6 和自动重载的脚手架,不过不用担心,我已经搭建了一个非常基本的 Webpack 脚手架,你可以从下面的链接克隆并进行设置。

GitHub 标志 ameerthehacker / webpack-starter-pack

这是一个非常基础的 webpack 配置,仅支持 ES6,其他一切都由您发挥创意来完成。

JSX

JSX 是一个开放标准,它并不局限于 React,所以我们可以在没有 React 的情况下使用它,而且它比你想象的要容易得多。为了理解我们如何将 JSX 应用于我们的库,让我们来看看使用 JSX 时幕后发生了什么。

const App = (
  <div>
    <h1 className="primary">QndReact is Quick and dirty react</h1>
    <p>It is about building your own React in 90 lines of JavsScript</p>
  </div>
);

// The above jsx gets converted into
/**
 * React.createElement(type, attributes, children)
 * props: it is the type of the element ie. h1 for <h1></h1>
 * attributes: it is an object containing key value pair of props passed to the element
 * children: it the array of child elements inside it
 */
var App = React.createElement(
  "div",
  null,
  React.createElement(
    "h1",
    {
      className: "primary"
    },
    "QndReact is Quick and dirty react"
  ),
  React.createElement(
    "p",
    null,
    "It is about building your own React in 90 lines of JavsScript"
  )
);
Enter fullscreen mode Exit fullscreen mode

如您所见,每个 JSX 元素都会被@babel /plugin-transform-react-jsx插件转换为 React.createElement(…) 函数调用,您可以在这里体验更多关于 JSX 到 JavaScript 的转换。

要实现上述转换,编写 JSX 时 React 必须位于作用域内。这就是为什么在 React 不在作用域内的情况下编写 JSX 时会遇到奇怪错误的原因。
我们首先来安装@babel /plugin-transform-react-jsx插件。

npm install @babel/plugin-transform-react-jsx 
Enter fullscreen mode Exit fullscreen mode

将以下配置添加到.babelrc文件中

{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "pragma": "QndReact.createElement", // default pragma is React.createElement
      "throwIfNamespace": false // defaults to true
    }]
  ]
}
Enter fullscreen mode Exit fullscreen mode

之后,每当 Babel 检测到 JSX 时,它都会调用QndReact.createElement(…),但我们还没有定义这个函数,所以让我们把它添加到src/qnd-react.js 文件中。

// file: src/qnd-react.js
const createElement = (type, props = {}, ...children) => {
  console.log(type, props, children);
};

// to be exported like React.createElement
const QndReact = {
  createElement
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

我们已经在控制台输出了type、props 和 children,以便了解传递给我们的参数是什么。为了测试我们对 JSX 的转换是否有效,让我们在src/index.js中编写一些 JSX 代码。

// file: src/index.js
// QndReact needs to be in scope for JSX to work
import QndReact from "./qnd-react";

const App = (
  <div>
    <h1 className="primary">
      QndReact is Quick and dirty react
    </h1>
    <p>It is about building your own React in 90 lines of JavsScript</p>
  </div>
);
Enter fullscreen mode Exit fullscreen mode

现在你应该会在控制台中看到类似这样的内容。

console.log JSX

根据以上信息,我们可以使用snabbdom创建自己的内部虚拟 DOM 节点,并将其用于我们的协调流程。首先,我们使用以下命令安装 snabbdom。

npm install snabbdom
Enter fullscreen mode Exit fullscreen mode

现在,每当调用QndReact.createElement(...)时,我们来创建并返回我们的虚拟 DOM 节点。

// file: src/qnd-react.js
import { h } from 'snabbdom';

const createElement = (type, props = {}, ...children) => {
  return h(type, { props }, children);
};

// to be exported like React.createElement
const QndReact = {
  createElement
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

现在我们能够解析 JSX 并创建自己的虚拟 DOM 节点了,但是仍然无法将其渲染到浏览器中。为此,我们需要在src/qnd-react-dom.js 文件中添加一个渲染函数。

// file: src/qnd-react-dom.js

// React.render(<App />, document.getElementById('root'));
// el -> <App />
// rootDomElement -> document.getElementById('root')
const render = (el, rootDomElement) => {
  // logic to put el into the rootDomElement
}

// to be exported like ReactDom.render
const QndReactDom = {
  render
};

export default QndReactDom;
Enter fullscreen mode Exit fullscreen mode

与其让我们自己费力地将元素添加到 DOM 中,不如让 snabbdom 来完成这项工作。为此,我们首先需要使用所需的模块初始化 snabbdom。snabbdom 中的模块类似于插件,它们允许 snabbdom 在需要时执行更多操作。

// file: src/qnd-react-dom.js
import * as snabbdom from 'snabbdom';
import propsModule from 'snabbdom/modules/props';

// propsModule -> this helps in patching text attributes
const reconcile = snabbdom.init([propsModule]);

// React.render(<App />, document.getElementById('root'));
// el -> <App />
// rootDomElement -> document.getElementById('root')
const render = (el, rootDomElement) => {
  // logic to put el into the rootDomElement
  reconcile(rootDomElement, el);
}

// to be exported like ReactDom.render
const QndReactDom =  { 
  render
};

export default QndReactDom;
Enter fullscreen mode Exit fullscreen mode

让我们使用全新的渲染函数在src/index.js中施展一些魔法吧。

// file: src/index.js
// QndReact needs to be in scope for JSX to work
import QndReact from './qnd-react';
import QndReactDom from './qnd-react-dom';

const App = (
  <div>
    <h1 className="primary">
      QndReact is Quick and dirty react
    </h1>
    <p>It is about building your own React in 90 lines of JavsScript</p>
  </div>
);

QndReactDom.render(App, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

瞧!我们应该能在屏幕上看到 JSX 渲染效果了。

jsx渲染

等等,我们遇到一个小问题,当我们两次调用 render 函数时,控制台会显示一些奇怪的错误。原因是,我们只能第一次在真正的 DOM 节点上调用reconcile方法,之后我们应该使用第一次调用时返回的虚拟 DOM 节点来调用它。

// file: src/qnd-react-dom.js
import * as snabbdom from 'snabbdom';
import propsModule from 'snabbdom/modules/props';

// propsModule -> this helps in patching text attributes
const reconcile = snabbdom.init([propsModule]);
// we need to maintain the latest rootVNode returned by render
let rootVNode;

// React.render(<App />, document.getElementById('root'));
// el -> <App />
// rootDomElement -> document.getElementById('root')
const render = (el, rootDomElement) => {
  // logic to put el into the rootDomElement
  // ie. QndReactDom.render(<App />, document.getElementById('root'));
  // happens when we call render for the first time
  if(rootVNode == null) {
    rootVNode = rootDomElement;
  }

  // remember the VNode that reconcile returns
  rootVNode = reconcile(rootVNode, el);
}

// to be exported like ReactDom.render
const QndReactDom =  { 
  render
};

export default QndReactDom;
Enter fullscreen mode Exit fullscreen mode

太好了,我们的应用程序中已经有了可用的 JSX 渲染,现在让我们来渲染一个函数组件,而不是一些纯 HTML。

让我们src/index.js添加一个名为Greeting 的功能组件,如下所示。

// file: src/index.js
// QndReact needs to be in scope for JSX to work
import QndReact from "./qnd-react";
import QndReactDom from "./qnd-react-dom";

// functional component to welcome someone
const Greeting = ({ name }) => <p>Welcome {name}!</p>;

const App = (
  <div>
    <h1 className="primary">
      QndReact is Quick and dirty react
    </h1>
    <p>It is about building your own React in 90 lines of JavsScript</p>
    <Greeting name={"Ameer Jhan"} />
  </div>
);

QndReactDom.render(App, document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

啊哦!控制台出现了一些错误,如下所示。

功能组件错误

让我们通过在QndReact.createElement(...)方法中添加 console.log 来查看发生了什么。

// file: src/qnd-react.js
import { h } from 'snabbdom';

const createElement = (type, props = {}, ...children) => {
  console.log(type, props, children);

  return h(type, { props }, children);
};

...

Enter fullscreen mode Exit fullscreen mode

功能组件控制台

我们可以看到,当组件是函数式组件时,传递的参数类型都是 JavaScript函数。调用该函数后,我们将得到组件想要渲染的 HTML 结果。

现在我们需要检查类型参数的类型是否为函数,如果是,则调用该函数作为type(props),如果不是,则将其作为普通的 HTML 元素处理。

// file: src/qnd-react.js
import { h } from 'snabbdom';

const createElement = (type, props = {}, ...children) => {
  // if type is a function then call it and return it's value
  if (typeof (type) == 'function') {
    return type(props);
  }

  return h(type, { props }, children);
};

// to be exported like React.createElement
const QndReact = {
  createElement
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

太棒了!我们的功能组件现在已经可以正常工作了。

功能组件工作

太棒了,我们已经做了很多,让我们深吸一口气,喝杯咖啡,拍拍自己的背,因为我们几乎完成了 React 的实现,我们只需要最后一块拼图——类组件。

小黄人欢呼

我们将在src/qnd-react.js中创建组件基类,如下所示。

// file: src/qnd-react.js
import { h } from "snabbdom";

const createElement = (type, props = {}, ...children) => {
  // if type is a function then call it and return it's value
  if (typeof type == "function") {
    return type(props);
  }

  return h(type, { props }, children);
};

// component base class
class Component {
  constructor() { }

  componentDidMount() { }

  setState(partialState) { }

  render() { }
}

// to be exported like React.createElement, React.Component
const QndReact = {
  createElement,
  Component
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

好的,让我们在src/counter.js中编写我们的第一个Counter类组件。

// file: src/counter.js
import QndReact from './qnd-react';

export default class Counter extends QndReact.Component {
  constructor(props) {
    super(props);

    this.state = {
      count: 0
    }
  }

  componentDidMount() {
    console.log('Component mounted');
  }

  render() {
    return <p>Count: {this.state.count}</p>
  }
}
Enter fullscreen mode Exit fullscreen mode

我知道我们还没有实现计数器的任何逻辑,但别担心,一旦我们的状态管理系统运行起来,我们就会添加这些功能。现在让我们尝试在src/index.js中渲染它。

// file: src/index.js
// QndReact needs to be in scope for JSX to work
import QndReact from "./qnd-react";
import QndReactDom from "./qnd-react-dom";
import Counter from "./counter";

// functional component to welcome someone
const Greeting = ({ name }) => <p>Welcome {name}!</p>;

const App = (
  <div>
    <h1 className="primary">
      QndReact is Quick and dirty react
    </h1>
    <p>It is about building your own React in 90 lines of JavsScript</p>
    <Greeting name={"Ameer Jhan"} />
    <Counter />
  </div>
);

QndReactDom.render(App, document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

正如预期的那样,控制台出现了一个错误 😉,如下所示。

类组件错误

上述错误看起来是否似曾相识?当您尝试在 React 中使用未继承自React.Component类的类组件时,就可能会遇到此错误。为了了解其原因,让我们在React.createElement(...)中添加console.log,如下所示。

// file: src/qnd-react.js
import { h } from "snabbdom";

const createElement = (type, props = {}, ...children) => {
  console.log(typeof (type), type);
  // if type is a function then call it and return it's value
  if (typeof type == "function") {
    return type(props);
  }

  return h(type, { props }, children);
};

...

Enter fullscreen mode Exit fullscreen mode

现在查看控制台,看看记录了什么。

类组件控制台

你可以看到 Counter 的类型也是一个函数,这是因为Babel最终会将 ES6 类转换为普通的 JavaScript 函数,那么我们该如何处理 Class 组件的情况呢?我们可以组件基类添加一个静态属性,用来检查传递的类型参数是否为 Class。React 也是这样处理的,你可以阅读 Dan 的博客了解更多信息(链接在此) 。

// file: src/qnd-react.js
import { h } from "snabbdom";

...

// component base class
class Component {
  constructor() { }

  componentDidMount() { }

  setState(partialState) { }

  render() { }
}

// add a static property to differentiate between a class and a function
Component.prototype.isQndReactClassComponent = true;

// to be exported like React.createElement, React.Component
const QndReact = {
  createElement,
  Component
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

现在让我们添加一些代码来处理QndReact.createElement(...)中的 Class 组件。

// file: src/qnd-react.js
import { h } from "snabbdom";

const createElement = (type, props = {}, ...children) => {
  // if type is a Class then
  // 1. create a instance of the Class
  // 2. call the render method on the Class instance
  if (type.prototype && type.prototype.isQndReactClassComponent) {
    const componentInstance = new type(props);

    return componentInstance.render();
  }
  // if type is a function then call it and return it's value
  if (typeof type == "function") {
    return type(props);
  }

  return h(type, { props }, children);
};

// component base class
class Component {
  constructor() { }

  componentDidMount() { }

  setState(partialState) { }

  render() { }
}

// add a static property to differentiate between a class and a function
Component.prototype.isQndReactClassComponent = true;

// to be exported like React.createElement, React.Component
const QndReact = {
  createElement,
  Component
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

太棒了!我们的类组件已经可以向浏览器渲染内容了。

类组件工作

呼!接下来我们来给 Class 组件添加状态。在此之前,需要理解的是,每次调用 ` this.setState({...})`时,DOM 的更新责任在于react-dom包,而不是 React。这样做是为了保持 React 的核心部分(例如组件类)与平台解耦,从而提高代码复用性。也就是说,在 React Native 中,你也可以使用相同的组件类,而react-native包则负责移动端 UI 的更新。你可能想知道 React 如何知道在调用`this.setState({...})`时该做什么,答案是 react-dom 通过在 React 中设置 ` __updater`属性来与 React 通信。Dan 也写了一篇关于此的优秀文章,你可以在这里阅读。现在,让我们为` QndReactDom`添加一个`__updater`属性。

// file: src/qnd-react-dom.js
import QndReact from './qnd-react';
import * as snabbdom from 'snabbdom';
import propsModule from 'snabbdom/modules/props';

...

// QndReactDom telling React how to update DOM
QndReact.__updater = () => {
  // logic on how to update the DOM when you call this.setState
}

// to be exported like ReactDom.render
const QndReactDom =  { 
  render
};

export default QndReactDom;
Enter fullscreen mode Exit fullscreen mode

每当我们调用this.setState({...})时,我们需要比较组件的oldVNode和通过调用组件的render函数生成的组件的newVNode,为了进行比较,让我们在类组件上添加一个__vNode属性来维护组件的当前 VNode 实例。

// file: src/qnd-react.js
import { h } from "snabbdom";

const createElement = (type, props = {}, ...children) => {
  // if type is a Class then
  // 1. create a instance of the Class
  // 2. call the render method on the Class instance
  if (type.prototype && type.prototype.isQndReactClassComponent) {
    const componentInstance = new type(props);

    // remember the current vNode instance
    componentInstance.__vNode = componentInstance.render();

    return componentInstance.__vNode;
  }
  // if type is a function then call it and return it's value
  if (typeof type == "function") {
    return type(props);
  }

  return h(type, { props }, children);
};

// component base class
class Component {
  constructor() { }

  componentDidMount() { }

  setState(partialState) { }

  render() { }
}

// add a static property to differentiate between a class and a function
Component.prototype.isQndReactClassComponent = true;

// to be exported like React.createElement, React.Component
const QndReact = {
  createElement,
  Component
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

现在让我们在Component基类中实现setState函数。

// file: src/qnd-react.js
import { h } from "snabbdom";

...

// component base class
class Component {
  constructor() { }

  componentDidMount() { }

  setState(partialState) {
    // update the state by adding the partial state
    this.state = {
      ...this.state,
      ...partialState
    }
    // call the __updater function that QndReactDom gave
    QndReact.__updater(this);
  }

  render() { }
}

// add a static property to differentiate between a class and a function
Component.prototype.isQndReactClassComponent = true;

// to be exported like React.createElement, React.Component
const QndReact = {
  createElement,
  Component
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

好了,现在让我们来处理QndReactDom中的__updater函数。

// file: src/qnd-react-dom.js
import QndReact from './qnd-react';
import * as snabbdom from 'snabbdom';
import propsModule from 'snabbdom/modules/props';

...

// QndReactDom telling React how to update DOM
QndReact.__updater = (componentInstance) => {
  // logic on how to update the DOM when you call this.setState

  // get the oldVNode stored in __vNode
  const oldVNode = componentInstance.__vNode;
  // find the updated DOM node by calling the render method
  const newVNode = componentInstance.render();

  // update the __vNode property with updated __vNode
  componentInstance.__vNode = reconcile(oldVNode, newVNode);
}

...

export default QndReactDom;
Enter fullscreen mode Exit fullscreen mode

太棒了!现在让我们通过向Counter 组件添加状态来检查setState实现是否有效。

import QndReact from './qnd-react';

export default class Counter extends QndReact.Component {
  constructor(props) {
    super(props);

    this.state = {
      count: 0
    }

    // update the count every second
    setInterval(() => {
      this.setState({
        count: this.state.count + 1
      })
    }, 1000);
  }

  componentDidMount() {
    console.log('Component mounted');
  }

  render() {
    return <p>Count: {this.state.count}</p>
  }
}
Enter fullscreen mode Exit fullscreen mode

太好了,我们的计数器组件已经按预期工作了。

反制措施

让我们添加ComponentDidMount生命周期钩子。Snabbdom 提供了一些钩子,通过这些钩子我们可以知道虚拟 DOM 节点是否在实际 DOM 中被添加、销毁或更新,您可以在这里了解更多信息。

// file: src/qnd-react.js
import { h } from "snabbdom";

const createElement = (type, props = {}, ...children) => {
  // if type is a Class then
  // 1. create a instance of the Class
  // 2. call the render method on the Class instance
  if (type.prototype && type.prototype.isQndReactClassComponent) {
    const componentInstance = new type(props);

    // remember the current vNode instance
    componentInstance.__vNode = componentInstance.render();

    // add hook to snabbdom virtual node to know whether it was added to the actual DOM
    componentInstance.__vNode.data.hook = {
      create: () => {
        componentInstance.componentDidMount()
      }
    }

    return componentInstance.__vNode;
  }
  // if type is a function then call it and return it's value
  if (typeof type == "function") {
    return type(props);
  }

  return h(type, { props }, children);
};

...

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

太好了,我们已经完成了支持 componentDidMount 生命周期钩子的 Class 组件的实现。

最后,我们来添加事件绑定支持。为此,我们需要更新Counter组件,添加一个名为“increment”的按钮,并仅在点击该按钮时才递增计数器。请注意,我们遵循的是常用的 JavaScript 事件命名约定,而不是 React 的命名约定,例如,双击事件应使用onDblClick而不是onDoubleClick

import QndReact from './qnd-react';

export default class Counter extends QndReact.Component {
  constructor(props) {
    super(props);

    this.state = {
      count: 0
    }
  }

  componentDidMount() {
    console.log('Component mounted');
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({
          count: this.state.count + 1
        })}>Increment</button>
      </div>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

上述组件无法正常工作,因为我们还没有告诉虚拟域如何处理它。首先,让我们将事件监听器模块添加到 Snabdom 中。

// file: src/qnd-react-dom.js
import * as snabbdom from 'snabbdom';
import propsModule from 'snabbdom/modules/props';
import eventlistenersModule from 'snabbdom/modules/eventlisteners';
import QndReact from './qnd-react';

// propsModule -> this helps in patching text attributes
// eventlistenersModule -> this helps in patching event attributes
const reconcile = snabbdom.init([propsModule, eventlistenersModule]);
...
Enter fullscreen mode Exit fullscreen mode

Snabdom 要求将文本属性事件属性作为两个独立的对象,所以我们就这样做。

// file: src/qnd-react.js
import { h } from 'snabbdom';

const createElement = (type, props = {}, ...children) => {
  ...

  props = props || {};
  let dataProps = {};
  let eventProps = {};

  // This is to seperate out the text attributes and event listener attributes
  for(let propKey in props) {
    // event props always startwith on eg. onClick, onDblClick etc.
    if (propKey.startsWith('on')) {
      // onClick -> click
      const event = propKey.substring(2).toLowerCase();

      eventProps[event] = props[propKey];
    }
    else {
      dataProps[propKey] = props[propKey];
    }
  }

  // props -> snabbdom's internal text attributes
  // on -> snabbdom's internal event listeners attributes
  return h(type, { props: dataProps, on: eventProps }, children);
};

...

// to be exported like React.createElement, React.Component
const QndReact = {
  createElement,
  Component
};

export default QndReact;
Enter fullscreen mode Exit fullscreen mode

现在,每次点击按钮时,计数器组件都会递增。

活动工作

太棒了!我们终于完成了 React 的快速简易实现,但是列表仍然无法渲染。我想把这个问题交给你,作为一项有趣的小任务。我建议你在src/index.js中尝试渲染一个列表,然后调试QndReact.createElement(...)方法,找出问题所在。

感谢您一路陪伴,希望您享受构建自己的 React 应用的过程,并在过程中学习到 React 的工作原理。如果您遇到任何问题,欢迎参考我下面分享的代码仓库。

GitHub 标志 ameerthehacker / qnd-react

我快速而简陋地实现了一个 React 版本,用来学习 React 的底层工作原理💥

快速简易 React 🔨

这是我为了帮助自己和其他人理解 React 底层工作原理而快速而简陋地实现的 React 版本。

这与文章《用 90 行 JavaScript 构建你自己的 React》非常契合。

  • ReactDom 的复制功能可在src/qnd-react-dom.js中找到。
  • React 的复制功能可在src/qnd-react.js中找到。

如何运行它?

  1. 克隆仓库
  2. 安装依赖项
npm install
Enter fullscreen mode Exit fullscreen mode
  1. 使用 QndReact.js 运行示例项目 ❤️
npm start
Enter fullscreen mode Exit fullscreen mode

发现任何问题吗?

欢迎随时提出问题或公关稿 😉

请通过给仓库点赞⭐来表达您的支持

执照

麻省理工学院 © Ameer Jhan




如果您想了解更多类似使用自定义虚拟 DOM 实现 React Fiber 的内容,请阅读这篇超棒的文章:《Didact:构建您自己的 React 的 DIY 指南》。

文章来源:https://dev.to/ameerthehacker/build-your-own-react-in-90-lines-of-javascript-1je2