Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EventEmitter and Subscriber ES6 Syntax with React Native

Tags:

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

  • React Native - Event Emitters by Colin Ramsay
  • React Native - Call Function of child from NavigatorIOS

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?

like image 537
Adam Jakiela Avatar asked Apr 21 '16 15:04

Adam Jakiela


People also ask

How do you use EventEmitter in react native?

import EventEmitter from "react-native-eventemitter"; .... componentWillMount() { let callback = (v)=>{ console.log("Main:", v); }; //监听1 EventEmitter.on("foo", (value)=>{ console.log("foo", value); }); //监听2 EventEmitter.on("foo", callback); //监听匹配EventEmitter.on("foo.*", (value)=>{ console.log("ALL", value); }); //条件 ...

What is ES6 in react native?

There's plenty of interesting history behind these naming conventions, but what you need to know is: ES6 is the “new” version of JavaScript, and extends the existing specification with some helpful new features. React Native uses Babel, the JavaScript compiler, to transform our JavaScript and JSX code.

Can I use EventEmitter in react?

JavaScript uses an event-driven programming model. Everything starts by subscribing to an event.


Video Answer


2 Answers

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);
    }
}
like image 59
Tom Avatar answered Sep 28 '22 07:09

Tom


This might be a very late answer, but I'm just going to put it out there for anyone who might find this useful.

As of the time of writing this answer (July, 2020), React Native has changed a lot since version 0.60.0+, you can either use an instance of EventEmitter, or statically call the DeviceEventEmitter methods.


Here is an example using EventEmitter:


import { EventEmitter } from 'events';

const newEvent = new EventEmitter();

// then you can use: "emit", "on", "once", and "off"
newEvent.on('example.event', () => {
  // ...
});


Another example using the DeviceEventEmitter:


import { DeviceEventEmitter } from 'react-native';

// then you can directly use: "emit", "addListener", and "removeAllListeners"
DeviceEventEmitter.emit('example.event', ['foo', 'bar', 'baz']);

Hope that comes handy for anyone who still looking for a way to implement custom events in React Native.

like image 39
Mohamed Gamil Avatar answered Sep 28 '22 07:09

Mohamed Gamil