目录
一、首先创建一个EventEmitter
二、events和useEventBus
三、使用events和useEventBus
1.同步调用
?2.异步调用
在开发react项目的时候,经常用到组件通信的场景,少不了EventBus,在ReactHook中如何使用EventBus呢?下面将详细介绍;
?
项目背景:本项目是基于react和TypeScript,其中主要是以ReactHook开发为主;
一、首先创建一个EventEmitter
新创建一个event-emitter.ts文件,在文件中放入如下代码:
import { pull } from 'lodash';
export type EventHandler<E = any> = (e: E) => void;
/*这个就是事件的原型*/
class EventEmitter<E = any> {
private _events: Record<string, EventHandler<E>[]>;
constructor() {
this._events = {};
}
private _getFns(event: string) {
return this._events[event] || (this._events[event] = []);
}
public on<T = E>(event: string, cb: EventHandler<T>) {
const fns = this._getFns(event);
fns.push(cb as any);
}
public off(event: string, cb?: EventHandler<E>) {
if (cb) {
const fns = this._getFns(event);
pull(fns, cb);
} else {
delete this._events[event];
}
}
public once<T = E>(event: string, cb: EventHandler<T>) {
const fn2: EventHandler<E> = (e) => {
this.off(event, fn2);
cb(e as any);
};
this.on(event, fn2);
}
/* 同步调用 */
public emit<T = E>(event: string, param?: T) {
const fns = this._getFns(event);
for (let i = 0; i < fns.length; i++) {
const fn = fns[i] as EventHandler<any>;
fn(param);
}
}
/* 可以异步调用,返回一个Promise */
public invoke<T = E>(event: string, param?: T): Promise<any> {
const fns = this._getFns(event);
flag: for (let i = 0; i < fns.length; i++) {
const fn = fns[i] as EventHandler<any>;
return new Promise<any>((resolve, reject) => {
resolve(fn(param));
});
break flag;
}
return Promise.reject();
}
}
export default EventEmitter;
二、events和useEventBus
创建events.ts文件,在文件中放入如下代码:
import EventEmitter, { EventHandler } from '@/common/event-emitter';
import { useEffect } from 'react';
const events = new EventEmitter();
export default events;
export function useEventBus<T = any>(
event: string,
cb: EventHandler<T>,
) {
useEffect(() => {
events.on(event, cb);
return () => {
events.off(event, cb);
};
});
}
三、使用events和useEventBus
现在有A组件和B组件,是两个没有任务关联的组件,无上下级关系的组件,要实现A组件向B组件传递数据,分为同步调用和异步调用两种情况,如下示例:
1.同步调用
同步调用的时候注意要用emit方法
import React from 'react';
import { Button } from 'antd';
/*引用上文声明好的events*/
import { events } from "@/common/events";
const ADemo = () => {
const handlePass = () => {
/*emit第一个参数的名称要跟useEventBus的第一个参数名称保持一致,建议语义化深刻一点;而且系统内要保持唯一*/
/*emit第二个参数,是传递给useEventBus的第二个参数所在函数的参数*/
events.emit('get:a:params', '哈哈哈**');
}
return (
<div>
ADemo:
<Button onClick={handlePass}>传递给B组件参数</Button>
</div>
);
};
export default ADemo;
import React, { useState } from "react";
/*引用上文声明好的useEventBus*/
import { useEventBus } from "@/common/events";
const BDemo = () => {
const [txt, setTxt] = useState<string>('');
const handleReceive = (params: string) => {
setTxt(params)
}
/* 对发出来的事件进行监听 */
useEventBus('get:a:params', handleReceive);
return (
<div>
BDemo接收到的参数:{txt || '空'}
</div>
);
};
export default BDemo;
在A组件中点击按钮,会把参数传递给B组件,在未点击前的状态如下:
?点击A组件中的按钮,B组件中接收到的参数如下:
?2.异步调用
异步调用要用invoke方法
import React, { useState } from "react";
import { Button } from 'antd';
/*引用上文声明好的events*/
import { events } from "@/common/events";
const ADemo = () => {
const [txt, setTxt] = useState<string>('');
const handlePass = () => {
/*emit第一个参数的名称要跟useEventBus的第一个参数名称保持一致,建议语义化深刻一点;而且系统内要保持唯一*/
/*emit第二个参数,是传递给useEventBus的第二个参数所在函数的参数*/
/*invoke方法返回一个promise,可以用then方法实现链式调用*/
events.invoke('async:pass:params', '哈哈哈**').then(res => {
setTxt(res)
});
}
return (
<div>
ADemo:
<Button onClick={handlePass}>传递给B组件参数</Button>
<span style={{ marginLeft: 18 }}>B组件返回给A的结果:{txt || "空"}</span>
</div>
);
};
export default ADemo;
import React, { useState } from "react";
/*引用上文声明好的useEventBus*/
import { useEventBus } from "@/common/events";
const BDemo = () => {
const [txt, setTxt] = useState<string>('');
const handleReceive = (params: string) => {
setTxt(params);
return '我成功传递了数据';
}
/* 对发出来的事件进行监听 */
useEventBus('async:pass:params', handleReceive);
return (
<div>
BDemo接收到的参数:{txt || '空'}
</div>
);
};
export default BDemo;
在A组件中点击按钮,会把参数传递给B组件,在未点击前的状态如下:
在A组件中点击按钮之后,页面效果如下:
以上就是本次分享的全部内容了,欢迎参考呀!
|