Event-driven architecture decouples components and enables scalable, maintainable code. At Google, we use it extensively in large SPAs.
Why Event-Driven?
Direct function calls create tight coupling. Events create loose coupling — the publisher doesn't know or care who's listening.
// Tight coupling
function addToCart(item) {
cartService.add(item);
analyticsService.track("add_to_cart", item);
notificationService.show("Added to cart");
recommendationService.update(item);
}
// Event-driven (loose coupling)
function addToCart(item) {
cartService.add(item);
eventBus.emit("cart:item-added", item);
}
// Each service listens independentlyCustom Event Bus
class EventBus {
#handlers = new Map();
on(event, handler) {
if (!this.#handlers.has(event)) this.#handlers.set(event, new Set());
this.#handlers.get(event).add(handler);
return () => this.off(event, handler);
}
off(event, handler) {
this.#handlers.get(event)?.delete(handler);
}
emit(event, payload) {
this.#handlers.get(event)?.forEach(h => {
try { h(payload); } catch (e) { console.error(e); }
});
}
once(event, handler) {
const wrapper = (payload) => {
handler(payload);
this.off(event, wrapper);
};
return this.on(event, wrapper);
}
}
export const eventBus = new EventBus();React Integration
function useEventBus(event, handler) {
useEffect(() => {
const unsub = eventBus.on(event, handler);
return unsub;
}, [event, handler]);
}
// Usage
function NotificationBar() {
const [message, setMessage] = useState("");
useEventBus("notification:show", (msg) => setMessage(msg));
return message ? <div className="notification">{message}</div> : null;
}Browser Custom Events
// Dispatch
window.dispatchEvent(new CustomEvent("app:theme-changed", {
detail: { theme: "dark" }
}));
// Listen
window.addEventListener("app:theme-changed", (e) => {
applyTheme(e.detail.theme);
});When NOT to Use Events
- For parent-child communication (use props)
- When you need a return value (events are fire-and-forget)
- When ordering matters (events are inherently unordered)
- For simple, direct communication between two components