React 发布-订阅者模式 实现组件之间的通信

React 发布-订阅者模式 实现组件之间的通信

React在实现组件之间通信时,对于“父-孙”,以及兄弟组件之间的信息传递,如果再使用props实现将会非常复杂,因此使用 “发布-订阅者模式” 将会简化这些操作。

原生JS中,dom事件中使用 target.addEventListener(type, listener, useCapture) 完成对事件的监听,也是最早的发布订阅者模式。

使用发布-订阅模式的优点在于,监听事件的位置和触发事件的位置是不受限的,这个特性,太适合用来应对“任意组件通信”这种场景了。

发布-订阅者模式API的设计思路

事件的监听(订阅)和事件的触发(发布),这两个动作自然而然地对应着两个基本的 API 方法。

  • on():负责注册事件的监听器,指定事件触发时的回调函数。
  • emit():负责触发事件,可以通过传参使其在触发的时候携带数据 。

最后,只进不出总是不太合理的,我们还要考虑一个 off() 方法,必要的时候用它来删除用不到的监听器:

  • off():负责监听器的删除。

API编码实现

class myEventEmitter {
  constructor() {
    // eventMap 用来存储事件和监听函数之间的关系
    this.eventMap = {};
  }
  // 订阅事件(监听事件) type 这里就代表事件的名称
  on(type, handler) {
    // hanlder 必须是一个函数,如果不是直接报错
    if (!(handler instanceof Function)) {
      throw new Error("请传一个函数");
    }
    // 判断 type 事件对应的队列是否存在
    if (!this.eventMap[type]) {
      // 若不存在,新建该队列
      this.eventMap[type] = [];
    }
    // 若存在,直接往队列里推入 handler
    this.eventMap[type].push(handler);
  }

  // 发布事件(触发事件)  可以携带数据的,params 就是数据的载体
  emit(type, params) {
    // 假设该事件是有订阅的(对应的事件队列存在)
    if (this.eventMap[type]) {
      // 将事件队列里的 handler 依次执行出队
      this.eventMap[type].forEach((handler, index) => {
        // 注意别忘了读取 params
        handler(params);
      });
    }
  }
  // 删除事件
  off(type, handler) {
    if (this.eventMap[type]) {
      this.eventMap[type].splice(this.eventMap[type].indexOf(handler) > 0, 1);
    }
  }
}

实现父子组件之间的通信

// 实例化 发布-订阅者模式的类
const globalEvent = new myEventEmitter();
// 兄弟组件B,订阅事件(监听事件)
class B extends React.Component {

  state = {
    newParams: ""
  };

  // 根据A组件中的数据,更新B数据的状态
  handler = (params) => {
    this.setState({
      newParams: params
    });
  };

  bindHandler = () => {
    globalEvent.on("someEvent", this.handler);
  };
  
  render() {
    return (
      <div>
        <button onClick={this.bindHandler}>点我监听A的动作</button>
        <div>A传入的内容是[{this.state.newParams}]</div>
      </div>
    );
  }
}

// 兄弟组件A, 发布事件(触发事件)
class A extends React.Component {

  state = {
    infoToB: "我来自A"
  };
  
  reportToB = () => {
    // 这里的 infoToB 表示 A 发送数据给 B 
    globalEvent.emit("someEvent", this.state.infoToB);
  };
  
  render() {
    return <button onClick={this.reportToB}>点我把state传递给B </button>
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值