前端开发中,不管是使用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打印出了参数: