You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+TypeScript中使用非React对象注入组件树实现多态的更新问题

实现方案

方案1:使用MobX实现响应式类状态(推荐)

这是最贴合OOP开发习惯的方案,几乎不需要改动原有多态逻辑,只需要给状态类加上响应式标识即可实现自动更新:

  1. 安装依赖:npm install mobx mobx-react
  2. 改造状态类为响应式:
import { makeObservable, observable, action } from "mobx";

class ClickCounter {
  private count: number = 0;
  constructor() {
    makeObservable(this, {
      count: observable,
      IncrementCount: action
    });
  }
  IncrementCount() {
    this.count += 1;
  }
  GetCount(): number {
    return this.count;
  }
}
  1. 给App组件添加observer装饰器,自动响应类状态变更:
import { observer } from "mobx-react";

@observer
export class App extends React.Component<{}, AppState> {
  // 原有代码完全不需要改动
}

该方案下,所有Operation实现类的内部状态变更都会被自动追踪,需要重渲染时MobX会自动触发组件更新,完全不需要手动传递刷新回调,也不破坏原有多态封装。

方案2:原生实现观察者模式(无第三方依赖)

如果不想引入额外库,可以自己实现轻量的变更通知机制:

  1. 扩展Operation接口,添加订阅能力:
interface Operation {
  HandleMouseDown(event: React.MouseEvent<HTMLDivElement>): void;
  GetComponents(): JSX.Element[];
  // 新增订阅方法,返回取消订阅的清理函数
  subscribe(changeCallback: () => void): () => void;
}
  1. 改造Operation实现类,状态变更时通知订阅者:
class ClickCounterOperation implements Operation {
  private clickCounter: ClickCounter;
  private subscribers: Set<() => void> = new Set();

  constructor() {
    this.clickCounter = new ClickCounter();
  }

  subscribe(callback: () => void) {
    this.subscribers.add(callback);
    return () => this.subscribers.delete(callback);
  }

  HandleMouseDown(_: React.MouseEvent<HTMLDivElement>): void {
    this.clickCounter.IncrementCount();
    // 状态变更后通知所有订阅者
    this.subscribers.forEach(cb => cb());
  }

  GetComponents(): JSX.Element[] {
    return [<div>you have clicked {this.clickCounter.GetCount()} times</div>];
  }
}
  1. 在App组件中订阅状态变更:
export class App extends React.Component<{}, AppState> {
  private unSubscribe?: () => void;

  constructor(props = {}) {
    super(props);
    const initialOperation: Operation = new ClickCounterOperation();
    this.state = {
      currentOperation: initialOperation,
    };
    // 订阅初始实例的状态变更,触发时强制组件重渲染
    this.unSubscribe = initialOperation.subscribe(() => this.forceUpdate());
    this.HandleMouseDown = this.HandleMouseDown.bind(this);
  }

  // 如果有运行时切换多态实例的需求,加上这个方法即可
  switchOperation(newOperation: Operation) {
    // 清理旧实例的订阅
    this.unSubscribe?.();
    // 订阅新实例的变更
    this.unSubscribe = newOperation.subscribe(() => this.forceUpdate());
    this.setState({ currentOperation: newOperation });
  }

  componentWillUnmount() {
    // 组件卸载时清理订阅,避免内存泄漏
    this.unSubscribe?.();
  }

  // 剩余原有逻辑保持不变
}

该方案没有任何第三方依赖,变更通知逻辑完全封装在Operation实现类内部,上层组件只需要做一次通用订阅,不需要给每个业务类传递定制化回调。

补充说明

两种方案都保留了你要的OOP多态特性,业务逻辑和状态完全封装在类内部,运行时切换多态实例的逻辑也不受影响,不需要把状态抽到外层组件或者全局store里,符合你的开发需求。


内容的提问来源于stack exchange,提问作者lsimmons

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 01:45:03