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?
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); }); //条件 ...
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.
JavaScript uses an event-driven programming model. Everything starts by subscribing to an event.
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);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With