Search code examples
react-nativemixinseventemitter

EventEmitter and Subscriber ES6 Syntax with React Native


I am trying to implement an EventEmitter/Subscriber relationship between two components in a react native class. I have seen referenced the following materials:

These solutions are adequate for what I am trying to accomplish, however, they bother require the use of mixins: [Subscribable.Mixin] on the receiving component to work properly with Subscriber. Unfortunately, I am using ES6 and extending my classes from Component so I can not use this mixin syntax.

My question is: How can I implement the above solutions in ES6 without the use of mixins?


Solution

  • You don't need mixins to use EventEmitters.

    Simple demo:

    import EventEmitter from 'EventEmitter';
    
    let x = new EventEmitter();
    
    function handler(arg) {
        console.log(`event-name has occurred! here is the event data arg=${JSON.stringify(arg)}`);
    }
    
    x.addListener('event-name', handler);
    
    x.emit('event-name', { es6rules: true, mixinsAreLame: true });
    

    The full signature for addListener takes three args:

    EventEmitter.addListener(eventName, handler, handlerContext)
    

    In a react component, you likely want to use that context arg, so that the handler can be a class method instead of an inline function and still retain this == component instance. E.g.:

    componentDidMount() {
        someEmitter.addListener('awesome', this.handleAwesomeEvents, this);
        // the generalist suggests the alternative:
        someEmitter.addListener('awesome', this.handleAwesomeEvents.bind(this));
    }
    
    handleAwesomeEvents = (event) => {
        let awesomeness = event.awesomeRating;
    
        // if you don't provide context in didMount,
        // "this" will not refer to the component,
        // and this next line will throw
        this.setState({ awesomeness });
    };
    

    FYI: I got this from looking at the decidedly unmagical implementation of the infamous Subscribable mixin. Google search results are basically an echo chamber of Ramsay's single mixin-based demo.

    P.S. As far as exposing this emitter to another component, I'd probably have the owning component provide a function for receiving the emitter reference, and the component that creates the emitter would then conditionally execute that prop with the emitter.

    // owner's render method:
    <ThingThatEmits
        onEmitterReady={(emitter) => this.thingEmitter = emitter}
    />
    
    // inside ThingThatEmits:
    componentDidMount() {
        this.emitter = new EventEmitter();
    
        if(typeof this.props.onEmitterReady === 'function') {
            this.props.onEmitterReady(this.emitter);
        }
    }