likes
comments
collection
share

使用发布订阅模式实现 react 跨组件通信

作者站长头像
站长
· 阅读数 63

使用发布订阅模式实现 react 跨组件通信

前言

公司内部一个很大型的项目,有两个毫不相关(组件层级上)的组件产生了联动效果,看上去效果很简单,但是作为一个开发,一眼就能看出来他的实现应该不简单,因为这两个组件之间跨了 N 多的层级,甚至可以说毫不相关的两个组件之间产生了联动。让我产生了浓厚的兴趣。

介绍一下场景

简化一下我们的项目场景,如下图

使用发布订阅模式实现 react 跨组件通信

有两个毫没关系的组件,A组件中有一个tab页签,点击tab就会切换下面对应的内容,A组件的实现如下

很简单就一个 activeIndex 状态控制显示的内容

使用发布订阅模式实现 react 跨组件通信

B组件中就3个按钮

使用发布订阅模式实现 react 跨组件通信

现在的需求就是,点击B的按钮,A组件能切换到对应的tab

思考

现在其实就是很简单的组件通信,我们能有巨多的实现方式。但是我们的项目很大,组件跨越的层级都没办法估计,就没有办法去在父级中统一管理状态。

那在仔细的想一下,现在这个需求实际上是需要干什么呢,B 去调 AsetState 方法对吧,那我们能不能把 A 组件的方法存在一个地方,然后在 B 中去使用呢?

bus,公共汽车

我们定义一个 bus 对象,啥都没有,就用来在公共的地方存数据

const Bus = {};
export default Bus;

然后在A组件中将A的方法存起来,为了让我们这个方法看起来不错,我们可以将存起来的方法命名进行规范一下,比如 组件名称_组件方法名称

使用发布订阅模式实现 react 跨组件通信

然后在B组件中调用

使用发布订阅模式实现 react 跨组件通信

OK 最终完美实现效果。

这样只是能实现,你要问他好吗,那在review代码的时候被喷肯定是跑不掉的。那有没有什么优雅的方式存呢?

发布订阅模式

发布订阅模式中,我们主要是需要能订阅事件,取消订阅事件,然后还需要有一个动作触发我们订阅的事件

我们维护一个 状态如下

const MessageState = {
  // 当前的状态
  state: {},
  // 订阅的消息列表
  subscriptions: [],
  // 更新状态,并且触发订阅的消息
  setState(state, skipCallbacks = false) {
    this.state = {
      ...this.state,
      ...state,
    };
    if (!skipCallbacks) {
      this.subscriptions.forEach((cb) => cb(this.state));
    }
  },
  // 获取状态
  getState() {
    return this.state;
  },
  // 订阅一个消息,返回值是取消订阅函数
  subscribe(cb) {
    this.subscriptions.push(cb);
    return () => {
      this.unsubscribe(cb);
    };
  },
  // 取消订阅
  unsubscribe(cb) {
    this.subscriptions = this.subscriptions.filter((item) => item !== cb);
  },
};

export default MessageState;

所谓的发布订阅,其实也就是有一个消息列表,订阅就是加一个事件到这个消息列表中,然后有一个时机,我们可以遍历这个消息列表,并且挨个执行他

OK,那我们看看在代码中应该怎么使用

修改一下我们的A组件,注册一个事件到我们的消息列表中

使用发布订阅模式实现 react 跨组件通信

B组件中,我们去触发一下

使用发布订阅模式实现 react 跨组件通信 OK,现在我们使用了发布订阅模式优雅的实现了我们的需求了。

注意点

我们的 MessageState 对象需要是单例的!!

然后在使用的时候需要注意一下单一职责,比如我们现在的 MessageState 他的职责主要是为了 A 服务的,复杂的场景下不要只用一个消息对象,要将他们拆分一下。

转载自:https://juejin.cn/post/7242623149752320058
评论
请登录