业务场景:有A和B两个表格,互为兄弟组件,当A中某个事件调用完成之后需要触发B表格中的更新。
解决办法:使用发布-订阅模式,在A表格中订阅事件,等B表格中发布后通知它
代码实现:
export class SubscriptionPublish {
private eventMap: Record<string, ((params: any) => any)[]>;
constructor() {
this.eventMap = {};
}
/**
* 订阅函数
* @param key 订阅事件Key值
* @param handler 订阅事件
*/
on(key: string, handler: (params: any) => any) {
if (!this.eventMap[key]) {
this.eventMap[key] = [];
}
this.eventMap[key].push(handler);
}
/**
* 发布函数
* @param key 订阅事件Key值
* @param params 要发步到订阅事件中的参数
*/
emit(key: string, params?: any) {
if (this.eventMap[key]) {
this.eventMap[key].forEach((handler) => {
handler(params);
});
}
}
/**
* 销毁函数
* @param key
* @param handler
*/
remove(key: string, handler: (params: any) => any) {
if (this.eventMap[key]) {
// 如果该队列存在,先找到要删除函数的位置,然后剔除
const res = this.eventMap[key].indexOf(handler);
res !== -1 && this.eventMap[key].splice(res, 1);
}
}
}
// 创建一个全局实例
const defaultEvent = new SubscriptionPublish();
export default defaultEvent;
代码使用:我们在写完发布-订阅类的代码之后在里面创建一个实例,用作全局使用
- A表格
const ApiTable: FC= () => {
// ...省略其他业务代码
// 刷新列表方法
const loadApi = () => {
table.reload();
};
useEffect(() => {
// 订阅刷新方法
defaultEvent.on('loadApi', loadApi);
return () => {
// 组件销毁时,销毁订阅函数
defaultEvent.remove('loadApi', loadApi);
};
}, []);
return (
<>
// ...业务代码
</>
);
};
export default ApiTable;
- B表格
const Index: FC = () => {
// ...省略其他业务代码
// 这里是要触发发布的地方
const handleSubmit = useCallback(async () => {
// ...省略其他逻辑处理
// 发布后,订阅函数调用
defaultEvent.emit('loadApi');
}, []);
return (
// ...业务代码
);
};
export default Index;
发布-订阅模式专门用于解决兄弟组件间通信的问题,不局限于 React ,其他的地方原理是一样的,同样可以解决类似问题的还有观察者模式。我这里只是针对于我这样的业务场景下写的