跨组件通信有哪些方式?其实我想说的是事件总线
谈到组件通信
大家的第一反应都是 父子组件通信
那么 跨组件的通信方式呢
说到跨组件通信
相信大家很第一反应 都能想到
-
Context API: React 的 Context API 允许你在组件树中传递数据而不必通过 props 手动传递。适用于需要在多个组件中共享数据的场景。
// 创建 Context const MyContext = React.createContext(); // 提供 Context function App() { return ( <MyContext.Provider value="Hello from context"> <ComponentA /> <ComponentB /> </MyContext.Provider> ); } // 使用 Context function ComponentA() { return ( <MyContext.Consumer> {value => <p>{value}</p>} </MyContext.Consumer> ); } function ComponentB() { const value = React.useContext(MyContext); return <p>{value}</p>; }
-
状态管理库: 使用像 Redux、MobX 或 Zustand 这样的状态管理库来管理和共享全局状态,适用于大型应用或需要复杂状态管理的场景。
// 使用 Redux // actions.js export const setMessage = (message) => ({ type: 'SET_MESSAGE', payload: message }); // reducer.js const initialState = { message: "" }; export function messageReducer(state = initialState, action) { switch (action.type) { case 'SET_MESSAGE': return { ...state, message: action.payload }; default: return state; } } // App.js import { useSelector, useDispatch } from 'react-redux'; import { setMessage } from './actions'; function ComponentA() { const dispatch = useDispatch(); return <button onClick={() => dispatch(setMessage("Hello from Redux"))}>Send Message</button>; } function ComponentB() { const message = useSelector(state => state.message); return <p>{message}</p>; }
事件总线
- 自定义事件总线: 对于不易直接通过 props 或状态管理解决的场景,可以使用自定义事件总线(Event Bus),如使用 Node.js 的
EventEmitter
或类似库来实现。
其实 在某些场景中 事件总线真的很有用 那么 这个模式一般有什么场景使用呢?
事件总线(Event Bus)是一种用于组件间通信的模式,适用于需要解耦和广播事件的场景。它可以在不同组件或模块之间传递事件,而不需要直接依赖于彼此。以下是一些常见的事件总线使用场景:
1. 解耦组件
- 无关组件间的通信:当两个组件没有直接父子关系时,可以使用事件总线来实现它们之间的通信,而不必通过 props 或 Context 传递数据。
- 插件系统:在插件系统中,插件可以通过事件总线与主应用进行通信,而不需要直接耦合。
2. 全局事件管理 这个真的很有用
- 全局状态通知:对于全局性事件(如用户登录、主题更改等),可以通过事件总线来广播通知,所有订阅了这些事件的组件都可以接收到通知并进行相应的处理。
- 应用级通知:例如,在应用的不同部分(如侧边栏、头部、底部)需要同步状态或处理相同的事件时,事件总线可以作为一个集中管理的解决方案。
3. 异步操作处理
- 任务完成通知:当一个异步任务(如数据加载、文件上传)完成时,可以通过事件总线通知其他相关组件更新其状态或进行后续操作。
- 操作结果广播:在复杂的操作中,多个组件可能需要知道操作结果,事件总线可以用来广播这些结果。
4. 模块化设计
- 模块间通信:在大型应用中,不同的功能模块可能需要相互通信。事件总线允许模块之间解耦合,同时保持灵活性和可扩展性。
- 组件库:在组件库中,各个组件可能需要响应全局事件或广播事件,事件总线是一种适合的实现方式。
5. 跨页面通信
- 单页面应用:在单页面应用(SPA)中,事件总线可以用于跨视图或跨页面的事件通信。
- Tab 之间通信:虽然现代浏览器提供了更复杂的跨页面通信机制(如 BroadcastChannel API),事件总线可以在同一页面内的多个组件间进行有效通信。
实现示例
使用 JavaScript 的 EventEmitter 实现事件总线:
// eventBus.js
import EventEmitter from 'events';
const eventBus = new EventEmitter();
export default eventBus;
发送事件:
// ComponentA.js
import React from 'react';
import eventBus from './eventBus';
function ComponentA() {
const sendMessage = () => {
eventBus.emit('message', 'Hello from ComponentA');
};
return <button onClick={sendMessage}>Send Message</button>;
}
export default ComponentA;
接收事件:
// ComponentB.js
import React, { useEffect, useState } from 'react';
import eventBus from './eventBus';
function ComponentB() {
const [message, setMessage] = useState('');
useEffect(() => {
const handleMessage = (msg) => {
setMessage(msg);
};
eventBus.on('message', handleMessage);
return () => {
eventBus.off('message', handleMessage);
};
}, []);
return <p>{message}</p>;
}
export default ComponentB;
注意事项
- 性能:在高频率的事件发送和接收场景中,事件总线可能会导致性能问题,需要考虑优化方案。
- 调试:由于事件总线在组件间传递数据不通过直接的 props 或 state,调试可能会变得更加复杂。
- 命名冲突:确保事件名称具有唯一性,以避免命名冲突带来的问题。
事件总线是一种强大的工具,但也需要谨慎使用,确保其在应用中的使用符合最佳实践,并且不会引入不必要的复杂性。
事件总线涉及到什么设计模式呢?
事件总线(Event Bus)涉及的设计模式主要包括以下几种:
1. 观察者模式(Observer Pattern)
定义:观察者模式是一种行为设计模式,其中一个对象(称为主题或被观察者)维护一组依赖于它的对象(称为观察者)。当被观察者发生变化时,它会通知所有观察者,以便它们更新其状态。
在事件总线中的应用:
- 事件总线作为主题:事件总线充当了观察者模式中的“主题”,发布事件。
- 组件作为观察者:订阅事件的组件充当“观察者”,当事件发生时,事件总线通知所有订阅者。
示例:
class EventBus {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
off(event, listener) {
if (!this.events[event]) return;
this.events[event] = this.events[event].filter(l => l !== listener);
}
emit(event, ...args) {
if (!this.events[event]) return;
this.events[event].forEach(listener => listener(...args));
}
}
2. 发布/订阅模式(Publish/Subscribe Pattern)
定义:发布/订阅模式是一种消息传递模式,其中发布者发送消息到一个消息通道,而订阅者从该消息通道接收消息。发布者和订阅者之间不直接通信。
在事件总线中的应用:
- 发布者:在事件总线中,发布事件的部分充当“发布者”。
- 订阅者:订阅事件的部分充当“订阅者”,它们通过事件总线接收消息。
示例:
const eventBus = new EventBus();
eventBus.on('eventName', data => {
console.log('Received event data:', data);
});
eventBus.emit('eventName', { key: 'value' });
3. 中介者模式(Mediator Pattern)
定义:中介者模式是一种行为设计模式,通过定义一个中介对象来封装一组对象之间的交互。中介者使得各个对象之间的通信通过中介对象进行,从而降低了它们之间的耦合度。
在事件总线中的应用:
- 事件总线作为中介者:事件总线充当中介者,负责协调各个组件或模块之间的通信和数据交换。
示例:
class Mediator {
constructor() {
this.channels = {};
}
subscribe(channel, listener) {
if (!this.channels[channel]) {
this.channels[channel] = [];
}
this.channels[channel].push(listener);
}
publish(channel, data) {
if (!this.channels[channel]) return;
this.channels[channel].forEach(listener => listener(data));
}
}
4. 消息传递模式(Message Passing Pattern)
定义:消息传递模式是一种设计模式,通过传递消息来实现对象之间的通信。这种模式允许系统中的不同部分通过发送和接收消息进行交互。
在事件总线中的应用:
- 事件总线作为消息通道:事件总线充当消息通道,通过发布和订阅机制实现消息传递。
示例:
class MessageBus {
constructor() {
this.subscribers = {};
}
subscribe(channel, handler) {
if (!this.subscribers[channel]) {
this.subscribers[channel] = [];
}
this.subscribers[channel].push(handler);
}
publish(channel, message) {
if (!this.subscribers[channel]) return;
this.subscribers[channel].forEach(handler => handler(message));
}
}
总结
- 观察者模式:事件总线实现了主题-观察者关系,使得组件能够订阅和响应事件。
- 发布/订阅模式:事件总线通过发布和订阅机制实现组件间的消息传递。
- 中介者模式:事件总线作为中介者,协调不同组件之间的通信。
- 消息传递模式:事件总线通过消息传递实现不同组件间的数据交换。
这些设计模式在事件总线中有机地结合在一起,使其成为一种有效的组件间通信和解耦工具。
转载自:https://juejin.cn/post/7398747326070702089