JavaScript 发布-订阅设计模式实现 React EventBus(相当于vue的$Bus)非父子之间通信
提前声明: 我没有对传入的参数进行及时判断而规避错误,仅仅对核心方法进行了实现;
解决了react的非父子间的通信;
参考文档:https://github1s.com/browserify/events/blob/main/events.js
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)非父子之间通信的更多相关文章
- JavaScript发布/订阅实例
原文链接: Pub/Sub JavaScript Object原文日期: 2014年6月11日翻译日期: 2014年6月13日 翻译人员: 铁锚 高效AJAX网站的三大杀器: 事件代理, 浏览历史管理 ...
- 三大前端框架(react、vue、angular2+)父子组件通信总结
公司业务需要,react.vue.angular都有接触[\无奈脸].虽然说可以拓展知识广度,但是在深度上很让人头疼.最近没事的时候回忆各框架父子组件通信,发现很模糊,于是乎稍微做了一下功课,记录于此 ...
- javaScript 自定义事件、发布订阅设计模式
现在很多应用都允许用户根据自己的喜好订阅一些自己较为关注的信息,当应用更新了这些信息后将针对不同的订阅类型推送此类信息.例如xx招聘网,当你订阅了互联网IT技术相关分类的招聘信息推送后,当企业在该网站 ...
- Javascript设计模式之发布-订阅模式
简介 发布-订阅模式又叫做观察者模式,他定义了一种一对多的依赖关系,即当一个对象的状态发生改变的时候,所有依赖他的对象都会得到通知. 回忆曾经 作为一名前端开发人员,给DOM节点绑定事件可是再频繁不过 ...
- js设计模式之发布订阅模式
1. 定义 发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知. 订阅者(Subscriber)把自己想订阅的事件注册(Subscri ...
- 观察者模式 vs 发布-订阅模式
我曾经在面试中被问道,_“观察者模式和发布订阅模式的有什么区别?” _我迅速回忆起“Head First设计模式”那本书: 发布 + 订阅 = 观察者模式 “我知道了,我知道了,别想骗我” 我微笑着回 ...
- 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码
最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...
- javascript设计模式——发布订阅模式
前面的话 发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模 ...
- [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1
<JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...
- 《JavaScript设计模式与开发实践》-- 发布-订阅模式
详情个人博客:https://shengchangwei.github.io/js-shejimoshi-fabudingyue/ 发布-订阅模式 1.定义 发布-订阅模式:发布-订阅模式又叫观察者模 ...
随机推荐
- Q:su命令切换用户无法使用,被拒绝
su命令切换用户无法使用,被拒绝 问题描述 su 命令报错 su: Permission denied 如下图: su 命令 报错 su: Permission denied,不管是su普通用户还是r ...
- Selenium常见方法
1.打开和关闭浏览器 打开浏览器 driver=webdriver.Ie() driver=webdriver.Chrome() driver=webdriver.Firefox() ...
- 介绍String、StringBuffer和StringBuilder
1. String类: 位于java.lang包,早期版本JDK1.0,继承Object类,实现java.io.Serializable, Comparable<String>, Cha ...
- 错误:为仓库 'appstream' 下载元数据失败 : Cannot prepare internal mirrorlist: No URLs in mirrorlist
sudo sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* sudo sed -i -e &qu ...
- RPA的数字化标签
随着中国经济的飞速发展,"人口红利"也正在不断消失,在过去几十年中,我们已经看到了各种智能化.自动化技术的进步对各行各业产生的巨大影响.但在现代金融行业中,仍然有许多重复.简单.繁 ...
- Python--相关环境的安装,以及hello world的实现
相关环境 进入官网:https://www.python.org/downloads/ 点击这里: 来到新的界面之后,向下滑动: 找到上图中的界面,选择版本进行下载即可. 具体的安装步骤可以参考这里看 ...
- 除select外查询数据的另一种姿势
1.24 1.[GYCTF2020]Blacklist buuctf上的题目 1.解题过程 输入1会返回一个数组,加上单引号就报错了,说明存在注入 以前做过类似的估计是堆叠注入,尝试一下 注入成功 正 ...
- Web自动化——介绍与安装以及第一个web自动化程序(一)
1. 为什么要做Web自动化测试 什么是web自动化测试 让程序代替人,去验证网页上功能的过程 web自动化测试与手工测试的比较 web自动化测试执行的测试用例是手工功能测试的子集 web自动化测试的 ...
- Linux常用命令 备查
区分关系: 有很多类型的shell,最常见的一种Shell是bash env 查看所有环境变量 用echo查看环境变量 echo $LOGNAME echo $PATH https://shimo.i ...
- 全局唯一ID的实现方案
为什么需要保证唯一ID? 在单机服务架构中,数据库的每一个业务表的主键ID都是允许自增的,但是在分布式服务架构的分库分表的设计,使得多个库或者多个表存储了相同的业务表,如果没有一个全局的唯一ID设计方 ...