实现一个组件通信工具EventProxy

387 阅读2分钟

前端开发中,不管是使用Angular、React,还是Vue,我们经常需要跨组件通信。父子组件间通信那还好办,但是兄弟组件之间的通信,实现起来就没那么方便了,起码在React中是如此。

这篇文章手把手教你实现一个在React中组件通信的工具:EventProxy,其实在其他框架中也是可以用的。

首先说一下思路:

1. 我们需要一个EventProxy对象,这个对象包含了若干属性和方法

2. 类里面需要一个对象类型的属性onObj,用来存储注册到EventProxy的事件

3. 此外还需要一个on方法,用来将事件加入到onObj里面

4. 还需要一个trigger方法,用来触发对应的事件

5. 最后需要一个off方法,用来取消订阅,以防内存泄漏

OK,说完思路,下面一步步编码实现。

首先定义EventProxy对象:

const EventProxy = {
  onObj: {},

  on: function() {},

  trigger: function() {},

  off: function() {}
}

export default EventProxy;

接着,实现on方法。

on方法需要接受两个参数,第一个是字符串key,用来唯一标记一个事件;第二个是一个函数fn,表示当事件触发的时候执行的回调。

当on方法被调用的时候,需要用key作用key值生成一个空数组作为onObj的属性。然后将fn塞进空数组(因为对于同一个事件,可能有多个不同的回调,因此需要用数组):

const EventProxy = {
  onObj: {},

  on: function(key, fn) {
    if(this.onObj[key] === undefined) {
      this.onObj[key] = [];
    }
    this.onObj[key].push(fn);
  },

  trigger: function() {},

  off: function() {}
}

export default EventProxy;

接下来,实现trigger方法。

首先trigger方法需要传入一个key,表示要触发哪个事件;然后会有不定长度的参数,用来传递额外参数:

const EventProxy = {
  onObj: {},

  on: function(key, fn) {
    if(this.onObj[key] === undefined) {
      this.onObj[key] = [];
    }
    this.onObj[key].push(fn);
  },

  trigger: function(key, ...rest) {
    if (arguments.length === 0) {
      return false;
    }
    if (this.onObj[key] !== undefined && this.onObj[key].length > 0) {
      this.onObj[key].forEach(fn => {
        fn.apply(null, rest);
      })
    }
  },

  off: function() {}
}

export default EventProxy;

最后,到了off方法。

这个方法很简单,只要传入一个key,然后清空对应key的数组,对应数组清空了,事件怎么触发回调函数都不会被调用了。

const EventProxy = {
  onObj: {},

  on: function(key, fn) {
    if(this.onObj[key] === undefined) {
      this.onObj[key] = [];
    }
    this.onObj[key].push(fn);
  },

  trigger: function(key, ...rest) {
    if (arguments.length === 0) {
      return false;
    }
    if (this.onObj[key] !== undefined && this.onObj[key].length > 0) {
      this.onObj[key].forEach(fn => {
        fn.apply(null, rest);
      })
    }
  },

  off: function(key) {
    this.onObj[key] = [];
  }
}

export default EventProxy;

到这里,我们的EventProxy就全部实现了,下面我们来测试一下:

import React, { Component } from 'react';

export default class Parent extends Component {

  render() {
    return (
      <>
        <Child1 />
        <Child2 />
      </>
    )
  }
}

import React, { Component } from 'react';
import EventProxy from './EventProxy.js';

export default class Child1 extends Component {

  handleClick = () => {
    EventProxy.trigger('click', '第一个参数', '第二个参数');
  }

  render() {
    return (
      <button onClick={this.handleClick}>click me</button>
    )
  }
}

import React, { Component } from 'react';
import EventProxy from './EventProxy.js';

export default class Child2 extends Component {
  componentDidMount() {
    EventProxy.on('click', (param1, param2) => {
      console.log(param1, param2);
    })
  }

  componentWillUnmount() {
    EventProxy.off('click');
  }

  render() {
    return null;
  }
}

点击Child1的按钮,Child2打印出了参数: