I am trying to implement an EventEmitter/Subscriber relationship between two components in a react native class. I have seen referenced the following materials:
I was able to get a workaround with react-mixin. Not sure how proper it is, but it works without any modification. The key is adding reactMixin(DetailView.prototype, Subscribable.Mixin);
after the class definition.
Going off the example that is floating around for EventEmitter and Subscribable:
'use strict';
var reactMixin = require('react-mixin');
var React = require('react-native');
var EventEmitter = require('EventEmitter');
var Subscribable = require('Subscribable');
var {
AppRegistry,
StyleSheet,
Text,
View,
NavigatorIOS
} = React;
class MainView extends Component {
constructor(props){
super(props);
this.EventEmitter = new EventEmitter();
}
somethingHappenedFunction(){
this.EventEmitter.emit("update_event", { message: "hello from up here"});
}
//rest of the class
}
class DetailView extends Component {
componentDidMount(){
this.addListenerOn(this.props.events, 'update_event', this.miscFunction);
}
miscFunction(args) {
console.log("message: %s", args.message);
}
//rest of the class
}
reactMixin(DetailView.prototype, Subscribable.Mixin);
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.
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);
}
}