JavaScript 发布-订阅设计模式实现 React EventBus(相当于vue的$Bus)非父子之间通信

这篇具有很好参考价值的文章主要介绍了JavaScript 发布-订阅设计模式实现 React EventBus(相当于vue的$Bus)非父子之间通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

提前声明: 我没有对传入的参数进行及时判断而规避错误,仅仅对核心方法进行了实现;

解决了react的非父子间的通信;

参考文档:https://github1s.com/browserify/events/blob/main/events.js

                 https://www.npmjs.com/package/events

                 https://github.com/browserify/events

                 

1.其中的一种实现的方式   

 

首先先新建一个文件eventBus.tsx

class EventBus {
  constructor() {
    this.events = this.events || new Map(); // 储存事件/回调键值对
    this.maxListeners = this.maxListeners || 10; // 设立监听上限
  }

  // 触发名为type的事件
  emit(type, ...args) {
    let handler = null;
    handler = this.events.get(type);
    console.log('🚀 ~ file: eventBus.js:11 ~ EventBus ~ emit ~ handler:', handler, args);
    if (handler === undefined) {
      return false;
    }
    if (Array.isArray(handler)) {
      // 如果是一个数组说明有多个监听者,需要依次此触发里面的函数
      // eslint-disable-next-line no-plusplus
      for (let i = 0; i < handler.length; i++) {
        if (args.length > 0) {
          handler[i].apply(this, args);
        } else {
          handler[i].call(this);
        }
      }
    } else {
      // 单个函数的情况我们直接触发即可
      // eslint-disable-next-line no-lonely-if
      if (args.length > 0) {
        handler.apply(this, args);
      } else {
        handler.call(this);
      }
    }
    return true;
  }

  // 监听名为type的事件
  on(type, fn) {
    const handler = this.events.get(type);
    if (!handler) {
      this.events.set(type, fn);
    } else if (handler && typeof handler === 'function') {
      // 如果handler是函数说明只有一个监听者
      this.events.set(type, [handler, fn]); // 多个监听者我们需要用数组储存
    } else {
      handler.push(fn); // 已经有多个监听者,那么直接往数组里push函数即可
    }
  }

  // eslint-disable-next-line consistent-return
  remove(type, fn) {
    const handler = this.events.get(type); // 获取对应事件名称的函数清单
    if (handler && typeof handler === 'function') {
      // 如果是函数,说明只被监听了一次
      this.events.delete(type, fn);
    } else {
      if (handler === undefined) {
        return false;
      }
      let position = null;
      // 如果handler是数组,说明被监听多次要找到对应的函数
      // eslint-disable-next-line no-plusplus
      for (let i = 0; i < handler.length; i++) {
        if (handler[i] === fn) {
          position = i;
        } else {
          position = -1;
        }
      }
      // 如果找到匹配的函数,从数组中清除
      if (position !== -1) {
        // 找到数组对应的位置,直接清除此回调
        handler.splice(position, 1);
        // 如果清除后只有一个函数,那么取消数组,以函数形式保存
        if (handler.length === 1) {
          this.events.set(type, handler[0]);
        }
      } else {
        return this;
      }
    }
  }
}

const eventBus = new EventBus();
export default eventBus;


// 简单实现的发布订阅模式 也是对的
// class EventEmitter {
//   constructor() {
//     this.eventBus = this.eventBus || {};
//   }

//   emit(type, params) {
//     this.eventBus.type.forEach(item => {
//       item(params);
//     });
//   }

//   on(type, fn) {
//     if (this.eventBus.type) {
//       this.eventBus.type.push(fn);
//     } else {
//       this.eventBus.type = [fn];
//     }
//   }

//   remove(type, fn) {
//     if (this.eventBus[type]) {
//       delete this.eventBus.type
//     }
//   }
// }

// const eventBus = new EventEmitter();
// export default eventBus;

然后再组件A使用=>接收

import React, { useState, useEffect, useCallback } from 'react';
// import eventBus from '@/utils/events';
import eventBus  from '@/utils/eventBus';

const TopBox = () => {
  const [num, setNum] = useState(0);

  const addNum = useCallback((message: any) => {
    setNum(message);
  }, []);

  useEffect(() => {
    eventBus.on('emit', addNum);
    return () => {
      if(eventBus) {
        eventBus.remove('emit', addNum);
      }
    };
  }, []);

  return (
    <div>
      <span>我也不知道是什么111: {num}</span>
    </div>
  );
};

export default TopBox;

然后再组件B使用=>触发

import React, { useState } from 'react';
import { Button } from 'antd';
// import eventBus from '@/utils/events';
import eventBus from '@/utils/eventBus';

const TopBox = () => {
  const [num,setNum] = useState(0)

  const addNum = () => {
    const numNew = num + 1;
    setNum(numNew);
    eventBus.emit('emit', numNew)
  }

  return (
    <div>
      <Button onClick={() => {addNum()}}>按钮</Button>
      <span>我也不知道是什么:{num}</span>
    </div>
  );
};

export default TopBox;

 

 

2.其中的另一种实现的方式

安装这个events插件

yarn add events

新建一个文件evnets.ts

import { EventEmitter } from 'events';
export default new EventEmitter();

组件A使用

import React, { useState, useEffect, useCallback } from 'react';
import eventBus from '@/utils/events';
// import eventBus  from '@/utils/eventBus';

const TopBox = () => {
  const [num, setNum] = useState(0);

  const addNum = useCallback((message: any) => {
    setNum(message);
  }, []);

  useEffect(() => {
    eventBus.on('emit', addNum);
    return () => {
      if(eventBus) {
        // eventBus.remove('emit', addNum);
        eventBus.removeListener('emit', addNum);
      }
    };
  }, []);

  return (
    <div>
      <span>我也不知道是什么111: {num}</span>
    </div>
  );
};

export default TopBox;

组件B使用

import React, { useState } from 'react';
import { Button } from 'antd';
import eventBus from '@/utils/events';
// import eventBus from '@/utils/eventBus';

const TopBox = () => {
  const [num,setNum] = useState(0)

  const addNum = () => {
    const numNew = num + 1;
    setNum(numNew);
    eventBus.emit('emit', numNew)
  }

  return (
    <div>
      <Button onClick={() => {addNum()}}>按钮</Button>
      <span>我也不知道是什么:{num}</span>
    </div>
  );
};

export default TopBox;

 文章来源地址https://www.toymoban.com/news/detail-417306.html

到了这里,关于JavaScript 发布-订阅设计模式实现 React EventBus(相当于vue的$Bus)非父子之间通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • js设计模式:发布订阅模式

    也称之为消息队列模式,或者pubsub模式 发布者发布消息(也可以理解为调用某函数),订阅者会收到消息,并且发布者可以将一些参数传递给订阅者。 是一种常用的参数传递方法,经典的pubsub.js,vue2中的$bus等都是用的这种模式。

    2024年02月19日
    浏览(48)
  • 设计模式之观察者(发布订阅)模式

    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同事监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己 观察者模式主要解决的问题: 当一个对象状态发生改变后给其他的对象通知 观察者的优点: 观察者和

    2024年02月07日
    浏览(47)
  • 设计模式(四) —— 观察者模式/发布订阅模式,c和c++示例代码

    往期地址: 设计模式(一)——简单工厂模式 设计模式(二)——策略模式 设计模式(三)——装饰模式 本期主题: 使用c和c++代码,讲解观察者模式、发布订阅模式 发布-订阅模式是一种行为设计模式,它允许多个对象通过事件的发布和订阅来进行通信; 在这种模式中,

    2023年04月17日
    浏览(43)
  • RabbitMQ学习——发布订阅/fanout模式 & topic模式 & rabbitmq回调确认 & 延迟队列(死信)设计

    1.rabbitmq队列方式的梳理,点对点,一对多; 2.发布订阅模式,交换机到消费者,以邮箱和手机验证码为例; 3.topic模式,根据规则决定发送给哪个队列; 4.rabbitmq回调确认,setConfirmCallback和setReturnsCallback; 5.死信队列,延迟队列,创建方法,正常—死信,设置延迟时间; 点对

    2024年02月13日
    浏览(73)
  • RabbitMQ基础(2)——发布订阅/fanout模式 & topic模式 & rabbitmq回调确认 & 延迟队列(死信)设计

    1.rabbitmq队列方式的梳理,点对点,一对多; 2.发布订阅模式,交换机到消费者,以邮箱和手机验证码为例; 3.topic模式,根据规则决定发送给哪个队列; 4.rabbitmq回调确认,setConfirmCallback和setReturnsCallback; 5.死信队列,延迟队列,创建方法,正常—死信,设置延迟时间; 点对

    2024年02月10日
    浏览(54)
  • JavaScript 简单实现观察者模式和发布-订阅模式

    大家好,我是南木元元,热衷分享有趣实用的文章。今天来聊聊设计模式中常用的观察者模式和发布-订阅模式。 观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。 如何理解这句话呢?来举个生活中的例子

    2024年02月12日
    浏览(88)
  • 4.设计模式之后七种模式后11种模式命令访问者迭代器发布订阅中介者忘备录解释器状态策略职责链和空模式

    1.命令(command)模式 不知道命令接收者(对象)是谁,支持撤销 (接受者 间接调用执行 的具体行为) 命令调用者和接收者解耦 //只要实现命令接口即可 (就是客户端给个命令,然后命令类传给接收类执行) 优点和缺点 容易撤销操作 命令队列可以多线程操作 增加过多的命令类 空命令也

    2024年02月12日
    浏览(57)
  • 设计模式 -- 策略模式(传统面向对象与JavaScript 的对比实现)

    规则:根据员工的工资基数和年底绩效情况计算年终奖 初级实现 缺点 多重 if else 违反开发-封闭原则,可维护性差 复用性差 使用组合函数重构代码 使用组合函数来重构代码,把各种算法封装到一个个的小函数里面,这些小函数有着良好的命名,可以一目了然地知道它对应着

    2024年02月11日
    浏览(65)
  • 【JavaScript】手撕前端面试题:寄生组合式继承 | 发布订阅模式 | 观察者模式

    🧑‍💼个人简介:大三学生,一个不甘平庸的平凡人🍬 🖥️ NodeJS专栏:Node.js从入门到精通 🖥️ 博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述) 🖥️ TypeScript知识总结:TypeScript从入门到精通(十万字超详细知识点总结) 👉

    2023年04月08日
    浏览(92)
  • 前端设计模式:工厂方法模式、单例模式、订阅模式、中介者模式

    工厂方法模式是一种创建型设计模式,它提供了一种将对象的创建与使用分离的方式。在工厂方法模式中,我们定义一个工厂接口,该接口声明了一个用于创建对象的方法。具体的对象创建则由实现该接口的具体工厂类来完成。 工厂方法模式的核心思想是将对象的创建延迟到

    2024年02月12日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包