Skip to content

React 虚拟 DOM 的设计模式

1. 代理模式

引申:VUE2 与 VUE3 的响应式原理,最大区别就是 VUE3 采用了 Proxy 代理,而 VUE2 采用的是 Object.defineProperty

核心思想:通过代理对象来间接操作真实对象,隐藏复杂实现细节。

javascript
class RealDOM {
  render() {
    console.log("Rendering the real DOM...");
  }
}

class VirtualDOMProxy {
  constructor() {
    this.realDOM = new RealDOM();
  }

  render() {
    console.log("Performing virtual DOM diff...");
    this.realDOM.render();
  }
}

const proxy = new VirtualDOMProxy();
proxy.render();
// Output:
// Performing virtual DOM diff...
// Rendering the real DOM...

2. 观察者模式

核心思想:虚拟 DOM 中状态变化会通知相关组件更新。

javascript
// 定义一个观察者类
class Observer {
  constructor() {
    // 初始化观察者对象时,创建一个空的订阅者数组
    // 该数组用于存储所有订阅了这个观察者的回调函数(观察者模式的订阅者)
    this.subscribers = [];
  }

  // 订阅方法,将传入的回调函数(订阅者)加入到订阅者数组中
  subscribe(fn) {
    // 将回调函数添加到订阅者列表
    this.subscribers.push(fn);
  }

  // 通知方法,当状态发生变化时,调用所有订阅者的回调函数
  notify(data) {
    // 遍历所有订阅者,并调用他们的回调函数,传入新的状态数据
    // 这里的 'data' 是状态数据,所有的订阅者都会得到这个数据更新
    this.subscribers.forEach((fn) => fn(data));
  }
}

// 创建一个观察者实例
const stateObserver = new Observer();

// 订阅:将一个回调函数添加到观察者的订阅者列表中
// 该回调函数会在通知方法调用时执行,接收状态数据并打印
stateObserver.subscribe((state) => console.log("State updated:", state));

// 模拟状态变化并通知所有订阅者
// 通过 notify 方法,状态更新时,会通知所有的订阅者,触发订阅者的回调
stateObserver.notify({ count: 1 });

3. 策略模式

核心思想:为虚拟 DOM 更新定义不同策略。

javascript
class UpdateStrategy {
  static replace() {
    console.log("Replacing the entire DOM node.");
  }

  static patch() {
    console.log("Patching the updated parts of the DOM.");
  }
}

function updateDOM(strategy = "patch") {
  UpdateStrategy[strategy]();
}

updateDOM("replace"); // Output: Replacing the entire DOM node.
updateDOM("patch"); // Output: Patching the updated parts of the DOM.

4. 单例模式

核心思想:虚拟 DOM 全局只有一个实例。

javascript
class VirtualDOMSingleton {
  constructor() {
    if (!VirtualDOMSingleton.instance) {
      this.tree = {};
      VirtualDOMSingleton.instance = this;
    }
    return VirtualDOMSingleton.instance;
  }
}

const dom1 = new VirtualDOMSingleton();
const dom2 = new VirtualDOMSingleton();
console.log(dom1 === dom2); // Output: true

5. 组合模式

核心思想:虚拟 DOM 的树状结构组织。

javascript
class VNode {
  constructor(type) {
    this.type = type;
    this.children = [];
  }

  addChild(node) {
    this.children.push(node);
  }

  render() {
    console.log(`Rendering ${this.type}`);
    this.children.forEach((child) => child.render());
  }
}

const root = new VNode("div");
const child1 = new VNode("span");
const child2 = new VNode("button");

root.addChild(child1);
root.addChild(child2);

root.render();
// Output:
// Rendering div
// Rendering span
// Rendering button

6. 工厂模式

核心思想:为虚拟 DOM 提供统一创建方法。

javascript
class VNode {
  constructor(type, props = {}) {
    this.type = type;
    this.props = props;
    this.children = [];
  }
}

class VNodeFactory {
  static create(type, props, children = []) {
    const node = new VNode(type, props);
    node.children = children;
    return node;
  }
}

const vNode = VNodeFactory.create("div", { id: "app" }, [
  VNodeFactory.create("h1", {}, ["Hello World"]),
]);

console.log(vNode);

7. 装饰器模式

核心思想:为虚拟 DOM 节点增强功能。

javascript
function withLogging(vNode) {
  vNode.log = function () {
    console.log(`VNode of type ${this.type}`);
  };
  return vNode;
}

let node = { type: "div" };
node = withLogging(node);
node.log(); // Output: VNode of type div

8. 命令模式

核心思想:将虚拟 DOM 的操作封装为命令。

javascript
class Command {
  constructor(execute) {
    this.execute = execute;
  }
}

class DOMCommands {
  static createElement(tag) {
    return new Command(() => console.log(`Creating element: <${tag}>`));
  }

  static removeElement(tag) {
    return new Command(() => console.log(`Removing element: <${tag}>`));
  }
}

const createDiv = DOMCommands.createElement("div");
createDiv.execute();

9. 迭代器模式

核心思想:遍历虚拟 DOM 树结构。

javascript
class VNode {
  constructor(type, children = []) {
    this.type = type;
    this.children = children;
  }

  *[Symbol.iterator]() {
    yield this;
    for (const child of this.children) {
      yield* child;
    }
  }
}

const tree = new VNode("div", [
  new VNode("h1"),
  new VNode("p", [new VNode("span")]),
]);

for (const node of tree) {
  console.log(node.type);
}
// Output:
// div
// h1
// p
// span

10. 享元模式

核心思想:复用相同的虚拟 DOM 节点。

javascript
class VNodeFactory {
  static nodes = {};

  static getNode(type) {
    if (!this.nodes[type]) {
      this.nodes[type] = new VNode(type);
    }
    return this.nodes[type];
  }
}

const node1 = VNodeFactory.getNode("div");
const node2 = VNodeFactory.getNode("div");

console.log(node1 === node2); // Output: true

11. 原型模式

核心思想:通过克隆生成新的虚拟 DOM。

javascript
class VNode {
  constructor(type, props) {
    this.type = type;
    this.props = props;
  }

  clone() {
    return new VNode(this.type, { ...this.props });
  }
}

const originalNode = new VNode("div", { id: "app" });
const clonedNode = originalNode.clone();

console.log(clonedNode); // Output: VNode { type: "div", props: { id: "app" } }

12. 适配器模式

核心思想:为虚拟 DOM 提供统一的接口,将不同结构或类型的输入转化为虚拟 DOM 可以识别的格式。

代码示例

javascript
class JSONToVNodeAdapter {
  static adapt(json) {
    const { type, props, children } = json;
    return new VNode(
      type,
      props,
      children.map((child) => JSONToVNodeAdapter.adapt(child))
    );
  }
}

class VNode {
  constructor(type, props = {}, children = []) {
    this.type = type;
    this.props = props;
    this.children = children;
  }
}

const jsonInput = {
  type: "div",
  props: { id: "app" },
  children: [{ type: "h1", props: {}, children: ["Hello World"] }],
};

const adaptedVNode = JSONToVNodeAdapter.adapt(jsonInput);
console.log(adaptedVNode);
// Output: A VNode object tree.

13. 模板方法模式

核心思想:为虚拟 DOM 的渲染定义固定的流程,但允许子类重写某些步骤以定制行为。

代码示例

javascript
class VirtualDOMRenderer {
  render(vNode) {
    this.beforeRender(vNode);
    this.renderNode(vNode);
    this.afterRender(vNode);
  }

  beforeRender(vNode) {
    console.log("Preparing to render:", vNode.type);
  }

  renderNode(vNode) {
    console.log("Rendering:", vNode.type);
    vNode.children.forEach((child) => this.render(child));
  }

  afterRender(vNode) {
    console.log("Finished rendering:", vNode.type);
  }
}

class CustomRenderer extends VirtualDOMRenderer {
  beforeRender(vNode) {
    console.log("Custom logic before rendering:", vNode.type);
  }
}

const renderer = new CustomRenderer();
const root = new VNode("div", {}, [new VNode("span"), new VNode("button")]);

renderer.render(root);

14. 中介者模式

核心思想:通过中介者协调虚拟 DOM 的不同部分,减少组件之间的直接依赖。

代码示例

javascript
class DOMMediator {
  constructor() {
    this.components = [];
  }

  register(component) {
    this.components.push(component);
    component.setMediator(this);
  }

  notify(sender, event) {
    console.log(`Mediator received ${event} from ${sender.type}`);
    this.components.forEach((component) => {
      if (component !== sender) component.receive(event);
    });
  }
}

class Component {
  constructor(type) {
    this.type = type;
    this.mediator = null;
  }

  setMediator(mediator) {
    this.mediator = mediator;
  }

  send(event) {
    console.log(`${this.type} sends ${event}`);
    this.mediator.notify(this, event);
  }

  receive(event) {
    console.log(`${this.type} received ${event}`);
  }
}

const mediator = new DOMMediator();
const div = new Component("div");
const span = new Component("span");

mediator.register(div);
mediator.register(span);

div.send("update");
// Output:
// div sends update
// Mediator received update from div
// span received update

15. 状态模式

核心思想:通过将虚拟 DOM 的状态分离,动态切换状态的行为。

代码示例

javascript
class VNode {
  constructor(type) {
    this.type = type;
    this.state = new DefaultState();
  }

  setState(state) {
    this.state = state;
  }

  render() {
    this.state.render(this);
  }
}

class DefaultState {
  render(vNode) {
    console.log(`${vNode.type} rendered in default state.`);
  }
}

class UpdatedState {
  render(vNode) {
    console.log(`${vNode.type} rendered in updated state.`);
  }
}

const node = new VNode("div");
node.render(); // Default state

node.setState(new UpdatedState());
node.render(); // Updated state

16. 备忘录模式

核心思想:保存虚拟 DOM 的状态以便在需要时恢复。

代码示例

javascript
class VNodeMemento {
  constructor(state) {
    this.state = state;
  }
}

class VNode {
  constructor(type, props) {
    this.type = type;
    this.props = props;
  }

  saveState() {
    return new VNodeMemento({ ...this.props });
  }

  restoreState(memento) {
    this.props = memento.state;
  }
}

const node = new VNode("div", { id: "app" });
const memento = node.saveState();

node.props.id = "new-app";
console.log(node.props); // { id: "new-app" }

node.restoreState(memento);
console.log(node.props); // { id: "app" }

17. 访问者模式

核心思想:为虚拟 DOM 的每个节点提供操作扩展,而无需改变其定义。

代码示例

javascript
class VNode {
  constructor(type, children = []) {
    this.type = type;
    this.children = children;
  }

  accept(visitor) {
    visitor.visit(this);
    this.children.forEach((child) => child.accept(visitor));
  }
}

class Renderer {
  visit(node) {
    console.log(`Rendering node: ${node.type}`);
  }
}

const tree = new VNode("div", [new VNode("span"), new VNode("button")]);
const renderer = new Renderer();

tree.accept(renderer);
// Output:
// Rendering node: div
// Rendering node: span
// Rendering node: button

18. 解释器模式

核心思想:解析虚拟 DOM 节点语法并执行。

代码示例

javascript
class Interpreter {
  static interpret(vNode) {
    if (typeof vNode === "string") {
      return document.createTextNode(vNode);
    }
    const element = document.createElement(vNode.type);
    for (const [key, value] of Object.entries(vNode.props || {})) {
      element.setAttribute(key, value);
    }
    (vNode.children || []).forEach((child) =>
      element.appendChild(Interpreter.interpret(child))
    );
    return element;
  }
}

const virtualDOM = {
  type: "div",
  props: { id: "app" },
  children: [
    { type: "h1", props: {}, children: ["Hello World"] },
    { type: "p", props: {}, children: ["This is a paragraph."] },
  ],
};

document.body.appendChild(Interpreter.interpret(virtualDOM));