React项目中使用发布订阅模式

React项目中使用发布订阅模式

发布订阅模式(也称观察者模式)是一种管理跨组件通信的有效方式,尤其是在不希望直接依赖于特定组件的情况下。这种模式允许一个对象(发布者)通知多个其他对象(订阅者),而不必知道这些对象是谁或他们在哪里。这有助于解耦组件,使得代码更加模块化和可维护。

1.创建发布订阅器

创建一个发布订阅器类,负责管理时间的注册、取消和触发

javascript 复制代码
# js
class PubSub {
	constructor(){
		this.events = {}
	}
	subscribe(event, callback){
		if(!this.events[event]){
			this.events[event] = []
		}
		this.events[event].push(callback)
	}
	unsubscribe(event,callback){
		if(this.events[event]){
			this.events[event] = this.events[event].filter(
				cb => cb !== callback
			)
		}
	}
	publish(event,data){
		if(this.events[event]){
			this.events[event].forEach(callback => callback(data))
		}
	}
}

const pubsub = new PubSub()
typescript 复制代码
# ts

interface EventMap {
  [eventName: string]: any;
}

class EventCenter {
  private listeners = {}

  constructor(){
    this.listeners = {}
  }
  subscribe<T extends keyof EventMap>(event: T, callback: (data?: EventMap[T]) => void) {
    if(!this.listeners[event]) {
      this.listeners[event] = []
    }
    this.listeners[event].push(callback)
  }

  publish<T extends keyof EventMap>(event: T, data?: EventMap[T]) {
    const callbacks = this.listeners[event]
    if(callbacks) {
      callbacks.forEach(callback => {
        callback(data)
      })
    }
  }

  unsubscribe<T extends keyof EventMap>(event: T, callback?: (data: EventMap[T]) => void) {
    const callbacks = this.listeners[event];
    if (callbacks) {
        if (callback) {
            this.listeners[event] = callbacks.filter(cb => cb !== callback);
        } else {
            delete this.listeners[event];
        }
    }
  }
}

export default new EventCenter()

2.在组件中使用发布订阅器

在你的React组件中使用这个发布订阅器。例如,一个组件可以订阅事件以接收数据,而另一个组件可以发布事件来发送数据。假设你有一个按钮组件,当点击时,他会触发一个事件发送一些数据

javascript 复制代码
import React from 'react';
import { pubsub } from './pubsub'; // 引入上面定义的PubSub实例

class ButtonComponent extends React.Component {
  handleClick = () => {
    pubsub.publish('dataUpdated', { message: 'Hello World!' });
  };

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me!
      </button>
    );
  }
}

3. 订阅数据

另一个组件可以订阅这个事件,并在接收到数据时执行某些操作

javascript 复制代码
import React, { useEffect, useState } from 'react';
import { pubsub } from './pubsub'; // 引入上面定义的PubSub实例

interface DisplayProps {}
interface DisplayState {
  message: string;
}

const DisplayComponent: React.FC<DisplayProps> = () => {
  const [message, setMessage] = useState('');

  useEffect(() => {
    const handleDataUpdate = ({ message }: { message: string }) => {
      setMessage(message);
    };

    pubsub.subscribe('dataUpdated', handleDataUpdate);

    return () => {
      pubsub.unsubscribe('dataUpdated', handleDataUpdate);
    };
  }, []);

  return <div>{message}</div>;
};

export default DisplayComponent;
相关推荐
古茗前端团队2 小时前
由 key 引发的思考
前端·javascript·react.js
kyriewen3 小时前
我扫了 422 个仓库,近一半 CI 在裸装依赖
前端·javascript·程序员
鹏多多3 小时前
AI 到底能不能独立做个产品?我拿一个小程序验证了
前端·微信小程序·ai编程
火山引擎开发者社区3 小时前
构建专属的飞书群开发助手,AgentKit Studio 一键部署 DeepSeek Harness Super-Agent
前端
啾咪orJIUMI5 小时前
Vue 3 + 高德地图封装实战:点位、区域、Loca 流光与 Vue 信息窗体
前端·vue.js
掘金者阿豪5 小时前
AI数据库不只是向量检索:从数据语义到库内智能计算的技术演进
前端
梦里寻码5 小时前
我用 NestJS + Vue3 写了一套完整的研发管理系统(58 表 / 229 API / 130 项断言,全开源
前端·后端·算法
FRing035 小时前
vue2干货总结8(路由模块封装、router-link、声明式导航、路由重定向、编程式导航)
开发语言·前端·vue.js·vue2
SameX5 小时前
HarmonyOS ArkUI Dialog 复用 用 @CustomDialog + enum type 做多类型统一管理的做法
前端
AiMan6 小时前
豆包爱学还是不可以导出左侧所有对话,只能单容导出,方法不对吗
前端