EventEmitter and Subscriber ES6 Syntax with React

2019-03-15 02:26发布

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?

2条回答
走好不送
2楼-- · 2019-03-15 03:21

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);
查看更多
贼婆χ
3楼-- · 2019-03-15 03:31

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);
    }
}
查看更多
登录 后发表回答