reactHook实现EventBus

本文详细介绍了如何在React项目中使用EventEmitter和useEventBus进行组件间的同步与异步通信,通过A、B组件示例展示了如何通过emit和invoke方法传递数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、首先创建一个EventEmitter

二、events和useEventBus

三、使用events和useEventBus

1.同步调用

 2.异步调用


在开发react项目的时候,经常用到组件通信的场景,少不了EventBus,在ReactHook中如何使用EventBus呢?下面将详细介绍;

项目背景:本项目是基于react和TypeScript,其中主要是以ReactHook开发为主;

EventBus原理

eventBus是一种在应用程序的不同组件之间进行通信的方式,它提供了一种简单且高效的方式来传递事件,从而实现了组件之间的解耦。

eventBus的实现原理基于观察者模式。观察者模式是一种软件设计模式,其中一个对象(称为观察者)将自己注册为另一个对象(主题)的观察者。当主题的状态发生变化时,它会通知所有观察者,使它们能够采取适当的行动。

eventBus的实现原理很简单的,它有一个中心事件总线,当一个组件发出一个事件时,它会通过总线发送这个事件。其他组件可以通过订阅总线上的事件来感知并响应这个事件。

一、首先创建一个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方法

  • A组件代码如下:
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;
  • B组件代码如下:
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组件,在未点击前的状态如下:

 点击A组件中的按钮,B组件中接收到的参数如下:

 2.异步调用

异步调用要用invoke方法

  •  A组件代码如下:
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;
  • B组件代码
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组件中点击按钮,会把参数传递给B组件,在未点击前的状态如下:

在A组件中点击按钮之后,页面效果如下:

以上就是本次分享的全部内容了,欢迎参考呀!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值