Pub Sub / Event Bus

Useful for when you don't want to include Redux, but would like to have events that can be triggered and listened to across unrelated components.


1) Create EventBus

I usually put this in src/Util/event_bus.js

event_bus.js
const EventBus = {
    /**
     * events stored as object with each field being an event
     */
    events: {},
    /**
     * Call all callbacks for given event
     * @param {string} event name of event
     * @param {*} data data sent to all event callbacks
     */
    dispatch: (event, data) => {
        if (!EventBus.events[event]) {
            return;
        }
        EventBus.events[event].forEach(callback => callback(data));
    },
    /**
     * @param event - the name of the event
     * @param callback - the function to be called
     */
    subscribe: (event, callback) => {
        if (!EventBus.events[event]) {
            EventBus.events[event] = [];
        }
        EventBus.events[event].push(callback);
    },
    /**
     * Must be called with the exact same callback as subscribe
     * as we match functions by their .toString()
     * @param event - the name of the event
     * @param callback - the function to be removed
     */
    unsubscribe: (event, callback) => {
        let newEvents = EventBus.events[event].filter((event) => {
            // hack to ensure we remove the right event
            if (!(callback.toString() == event.toString())) {
                return event;
            }
        })
        EventBus.events[event] = newEvents;
    }
}
 
export default EventBus;

2) Emit Events

// import eventbus to use
import EventBus from '../event_bus';

When you want to emit an event use the following:

EventBus.dispatch("eventName", this.state.dataToPass);

3) Subscribe to Events

componentWillMount(){
    EventBus.subscribe("eventName", this.handlerFunction);
}

4) Unsubscribe from Events

At some point you may want a component to stop listening for an event. Note: The second paramater to unsubscribe must exactly match the second parameter for subscribe. Eventuallly it would be worthwhile to handle this cleaner, but since I almost exclusively use this with function paramaters instead of inline functions the limitation isn't too bad.

componentWillMount(){
    EventBus.unsubscribe("eventName", this.handlerFunction);
}