Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Для чего нужен EventBus
EventBus — это паттерн для взаимодействия компонентов через события, без прямого соединения между ними. Это инструмент для связи между отдалёнными частями приложения.
Основная идея
Вместо того чтобы компоненты общались друг с другом напрямую, они обмениваются событиями через централизованный EventBus:
Компонент A: "Произошло событие X" -> [EventBus]
|
Компонент B: слушает событие X <- [EventBus]
Компонент C: слушает событие X <- [EventBus]
Пример простого EventBus
class EventBus {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event]
.filter(cb => cb !== callback);
}
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => {
callback(data);
});
}
}
}
const bus = new EventBus();
bus.emit('userLoggedIn', { userId: 123 });
bus.on('userLoggedIn', (user) => {
console.log('Пользователь вошёл:', user);
});
Основные проблемы, которые решает EventBus
1. Связанность компонентов (Coupling)
Без EventBus компоненты должны знать друг о друге:
function HeaderComponent() {
const notificationComponent = new NotificationComponent();
const handleUserLogin = (user) => {
notificationComponent.show(`Welcome, ${user.name}!`);
};
return <button onClick={handleUserLogin}>Login</button>;
}
function HeaderComponent() {
const handleUserLogin = (user) => {
eventBus.emit('notification', `Welcome, ${user.name}!`);
};
return <button onClick={handleUserLogin}>Login</button>;
}
function NotificationComponent() {
useEffect(() => {
eventBus.on('notification', (message) => {
showNotification(message);
});
}, []);
}
2. Коммуникация на расстоянии
Добраться до компонента глубоко в дереве без передачи props:
function LoginButton() {
const handleLogin = (user) => {
eventBus.emit('user:login', user);
eventBus.emit('notification:show', 'Welcome!');
eventBus.emit('counter:increment');
};
}
Когда использовать EventBus
Подходит для:
- Глобальные события (user logged in, theme changed)
- Коммуникация между компонентами разных модулей
- Системные события (network error, app initialized)
- Notifications, alerts, modals
eventBus.emit('theme:changed', 'dark');
eventBus.emit('user:logout');
eventBus.emit('api:error', { message: 'Server error' });
eventBus.emit('modal:open', { type: 'confirmation' });
eventBus.emit('toast:show', { message: 'Saved!' });
Не подходит для:
- Локальное состояние компонента (используй useState)
- Props между родителем и ребёнком (используй props)
- Состояние приложения (используй Redux/Zustand/Context)
EventBus в React (React Context как альтернатива)
В современном React часто используют Context вместо EventBus:
const UserContext = createContext();
function UserProvider({ children }) {
const [user, setUser] = useState(null);
const value = {
user,
setUser,
logout: () => setUser(null),
};
return (
<UserContext.Provider value={value}>
{children}
</UserContext.Provider>
);
}
function useUser() {
return useContext(UserContext);
}
function Header() {
const { user, logout } = useUser();
return <button onClick={logout}>Logout</button>;
}
EventBus с типизацией (TypeScript)
type EventMap = {
'user:login': { id: number; name: string };
'user:logout': void;
'notification:show': string;
'theme:change': 'light' | 'dark';
};
class TypedEventBus {
private events = new Map();
on(event, callback) {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event).push(callback);
}
emit(event, data) {
const callbacks = this.events.get(event) || [];
callbacks.forEach(cb => cb(data));
}
}
const eventBus = new TypedEventBus();
eventBus.emit('user:login', { id: 1, name: 'John' });
Проблемы с EventBus
1. Сложно отследить поток данных
eventBus.emit('something:happened', data);
2. Может привести к спагетти-коду Много событий, разные обработчики, сложная логика.
3. Утечки памяти
useEffect(() => {
eventBus.on('event', handler);
return () => eventBus.off('event', handler);
}, []);
Лучшие практики
- Используй строго типизированные события (TypeScript)
- Документируй все события в одном месте
- Отписывайся от событий при размонтировании
- Избегай цепочек событий
- Предпочитай Context или state management
Итог
EventBus нужен для:
- Связи между несвязанными компонентами
- Глобальных событий приложения
- Систем уведомлений и модалей
В современном React часто вместо EventBus используют React Context для глобального состояния, Zustand или Redux для сложного состояния, useCallback и props для локальной коммуникации.
EventBus — это мощный инструмент, но используй его только когда действительно нужна развязка компонентов.