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.定义 发布-订阅模式:发布-订阅模式又叫观察者模 ...
随机推荐
- 关于数据传递 json
关于这几种语言的json 操作 Lua local cjson2 = require "cjson" local lua_object = { ["name"] ...
- Angular架构学习
定义 Angular 是一个用 HTML 和 JavaScript 或者一个可以编译成 JavaScript 的语言(例如 Dart 或者 TypeScript ),来构建客户端应用的框架. 写 An ...
- 数据库结构差异比较-SqlServer
/****** Object: StoredProcedure [dbo].[p_comparestructure_2005] Script Date: 2022/10/8 10:00:20 **** ...
- 安装单机版k8s
1.配置yum源,博主使用华为的镜像源 选择不同的系统版本下载使用: 2.安装etcd,kubernetes yum -y install etcd kubernetes 3.修改kubernetes ...
- 【BUUCTF】ACTF2020 新生赛Include1 write up
查看源代码+抓包都没有发现什么信息,只有这两个东东 <meta charset="utf8"> Can you find out the flag? <meta ...
- pyecharts 学习使用网址
pyecharts新版官方手册地址:https://pyecharts.org/#/zh-cn/intro 或http://pyecharts.org/#/?id=pyecharts或http://p ...
- OD机试题-2022.4
import java.util.ArrayList;import java.util.Comparator;import java.util.List;import java.util.Scanne ...
- Android笔记--Android studio里面打开数据库详解
1.下载Database Navigator插件,然后需要重启Android studio 2.然后会总界面这里.出现这样一个图标 然后选中Database Brower: 3.弹出这样一个界面 然后 ...
- Java执行带空格的语句命令,cmd无法识别带空格路径的问题
带空格的会识别不了 先说解决方法: 1:用cmd中的start: 在JAVA中可以如此使用: Runtime.getRuntime().exec("cmd /c start \"\ ...
- C#MD5加密的两种方式
在开发过程当中,我们经常会用到MD5加密,下面介绍MD5加密的两种方式: /// <summary> /// MD5字符串加密 /// </summary> /// <p ...