Skip to content
patterns questions

Patterns · 5 of 10middle~1 min

What is the Observer pattern and how is it used in frontend?

#design-patterns#events

Observer Pattern

The observer pattern defines a one-to-many relationship: when one object (subject) changes state, all its dependents (observers) are notified automatically.

Core implementation

ts
class EventEmitter<T extends Record<string, unknown>> { private listeners: Partial<{ [K in keyof T]: ((data: T[K]) => void)[] }> = {}; on<K extends keyof T>(event: K, listener: (data: T[K]) => void) { if (!this.listeners[event]) this.listeners[event] = []; this.listeners[event]!.push(listener); return () => this.off(event, listener); // return unsubscribe } off<K extends keyof T>(event: K, listener: (data: T[K]) => void) { this.listeners[event] = this.listeners[event]?.filter(l => l !== listener); } emit<K extends keyof T>(event: K, data: T[K]) { this.listeners[event]?.forEach(l => l(data)); } } // usage type AppEvents = { 'user:login': { userId: string }; 'cart:updated': { count: number }; }; const emitter = new EventEmitter<AppEvents>(); const unsubscribe = emitter.on('user:login', ({ userId }) => { console.log('User logged in:', userId); }); emitter.emit('user:login', { userId: 'u1' }); unsubscribe(); // cleanup

Where you see it in frontend

  • DOM events - addEventListener / removeEventListener.
  • RxJS - Observable.subscribe().
  • Zustand - store.subscribe().
  • React Query - cache subscriptions.
  • WebSocket - socket.on('message', handler).

In React - custom event bus

tsx
// cross-component communication without prop drilling or shared state const bus = new EventEmitter(); // component A - emit function ButtonA() { return <button onClick={() => bus.emit('refresh', {})}>Refresh</button>; } // component B - listen function TableB() { useEffect(() => { return bus.on('refresh', () => refetch()); }, []); }

Observer is everywhere in frontend - the DOM event system itself is observer. The main risk is memory leaks from unremoved listeners - always clean up in useEffect return.

updated

did you know it?

read more on the blog

view all

related questions