提前声明: 我没有对传入的参数进行及时判断而规避错误,仅仅对核心方法进行了实现;
解决了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)的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did222230