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

解决了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;

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

  1. JavaScript发布/订阅实例

    原文链接: Pub/Sub JavaScript Object原文日期: 2014年6月11日翻译日期: 2014年6月13日 翻译人员: 铁锚 高效AJAX网站的三大杀器: 事件代理, 浏览历史管理 ...

  2. 三大前端框架(react、vue、angular2+)父子组件通信总结

    公司业务需要,react.vue.angular都有接触[\无奈脸].虽然说可以拓展知识广度,但是在深度上很让人头疼.最近没事的时候回忆各框架父子组件通信,发现很模糊,于是乎稍微做了一下功课,记录于此 ...

  3. javaScript 自定义事件、发布订阅设计模式

    现在很多应用都允许用户根据自己的喜好订阅一些自己较为关注的信息,当应用更新了这些信息后将针对不同的订阅类型推送此类信息.例如xx招聘网,当你订阅了互联网IT技术相关分类的招聘信息推送后,当企业在该网站 ...

  4. Javascript设计模式之发布-订阅模式

    简介 发布-订阅模式又叫做观察者模式,他定义了一种一对多的依赖关系,即当一个对象的状态发生改变的时候,所有依赖他的对象都会得到通知. 回忆曾经 作为一名前端开发人员,给DOM节点绑定事件可是再频繁不过 ...

  5. js设计模式之发布订阅模式

    1. 定义 发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知. 订阅者(Subscriber)把自己想订阅的事件注册(Subscri ...

  6. 观察者模式 vs 发布-订阅模式

    我曾经在面试中被问道,_“观察者模式和发布订阅模式的有什么区别?” _我迅速回忆起“Head First设计模式”那本书: 发布 + 订阅 = 观察者模式 “我知道了,我知道了,别想骗我” 我微笑着回 ...

  7. 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码

    最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...

  8. javascript设计模式——发布订阅模式

    前面的话 发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模 ...

  9. [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  10. 《JavaScript设计模式与开发实践》-- 发布-订阅模式

    详情个人博客:https://shengchangwei.github.io/js-shejimoshi-fabudingyue/ 发布-订阅模式 1.定义 发布-订阅模式:发布-订阅模式又叫观察者模 ...

随机推荐

  1. web自动化测试—Firefox安装与配置

    web自动化测试-Firefox安装与配置 下一步 下一步 下一步 下一步 下一步 下一步 下一步 下一步 下一步设置不更新 下一步添加插件 下一步 下一步 下一步 下一步立即重启 下一步查看插件 在 ...

  2. MySQL 日期相关

    NOW() 返回当前的日期和时间 CURDATE() 返回当前的日期 CURTIME() 返回当前的时间 DATE() 提取日期或日期/时间表达式的日期部分 EXTRACT() 返回日期/时间按的单独 ...

  3. FCC 高级算法题 库存更新

    Inventory Update 依照一个存着新进货物的二维数组,更新存着现有库存(在 arr1 中)的二维数组. 如果货物已存在则更新数量 . 如果没有对应货物则把其加入到数组中,更新最新的数量. ...

  4. JS this指向相关

    function Foo() { getName = function() { console.log(1) } return this;}Foo.getName = function() { con ...

  5. maven本地仓库有相应的依赖,依旧会从远程仓库拉取问题的原因及解决

    请打开你自己的本地仓库,对应依赖路径下的_remote.repositories文件.如果是从远程仓库拉取的,这里一般是显示这个: junit-4.12.jar>alimaven= junit- ...

  6. MybatisPlus 实现多表联合分页条件查询

    方式一:XML 有点繁琐,不太想用 mapper接口 public interface RoomMapper extends BaseMapper<Room> { List<Room ...

  7. Python第一次作业(20220909)

    实例01:根据身高.体重计算BMI指数 ①:分别定义两个变量"height"和"weight",用于储存身高(单位:米)和体重(单位:千克).使用内置的prin ...

  8. pushd 和 popd:对目录栈进行操作

    介绍 目录栈是保存目录的栈结构,当前目录处于该栈结构的顶端,可使用dirs查看目录栈的目录.pushd命令可添加一个目录到目录栈,popd命令会清除目录栈中的一个目录. dirs dirs有三个参数: ...

  9. 与NewBing一起写作:《Web应用安全入门》

    前言 本文内容基于我的<Web应用安全入门>公开课视频. Prompt:下面是一篇课程音频转录后的文本,请把它转成老师和学生对话形式的文本,要求遵循原文结构,语言衔接流畅,保持 Markd ...

  10. Z 函数

    简单记一下,避免忘记. z 函数 对于字符串 \(S\),我们将 \(z(i)\) 定义为从 \(i\) 开始的后缀与 \(S\) 的最长公共前缀的长度. \(O(n)\) 求出 z 函数 我们添加一 ...