事件发射器和订阅者ES6语法在React Native中的应用

25
我正在尝试在React Native类中的两个组件之间实现EventEmitter / Subscriber关系。我已经参考了以下材料: 这些解决方案对于我想要完成的任务是足够的,但是它们都需要在接收组件上使用`mixins:[Subscribable.Mixin]`才能与Subscriber正常工作。不幸的是,我正在使用ES6并从Component扩展我的类,因此我不能使用这种mixin语法。
我的问题是:如何在ES6中实现上述解决方案而不使用mixin?

这里有人建议简单地使用“旧方法”编写组件:http://hi-tips.tumblr.com/post/137014836571/use-eventemitter-for-calling-child-component-event我也遇到了同样的问题,想知道在ES6中是否有任何适当的方法来解决它。 - Patrick Riemer
我还在寻找这个。我不愿意开始使用 react-mixin - Tom
4个回答

37
你不需要使用mixin来使用EventEmitters。
简单演示:
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 });
< p > addListener 的完整签名需要三个参数:

EventEmitter.addListener(eventName, handler, handlerContext)

在一个React组件中,您可能希望使用上下文参数,这样处理程序可以是类方法而不是内联函数,并且仍然保留this == 组件实例。例如:
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 });
};

注意:我是通过查看绝非神奇的Subscribable mixin实现得出这个结论的。Google 搜索结果基本上是 Ramsay 的单个 mixin 演示的回声室。
另外,如果要将此发射器暴露给另一个组件,我可能会让拥有该组件的组件提供一个函数来接收发射器引用,然后创建发射器的组件将使用该发射器条件地执行该 prop。
// 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);
    }
}

1
谢谢!你的“简单演示”正是我需要看到的,让我恍然大悟。 - iksnae
嗨Tom,当我尝试调用 let test = new EventEmitter(); 时,它会抛出 undefined is not a constructor (evaluating 'new _reactNative.EventEmitter()') 的错误。你对此有什么想法吗? - Richard
@Richard:没有。你使用的是哪个版本的React Native?你确定你已经正确导入了吗?你尝试重新启动RN打包器了吗?这是编译时还是运行时失败? - Tom
1
我知道回复有点晚了,但你应该这样导入:import EventEmitter from "EventEmitter"; 而不是这样:import { EventEmitter } from "EventEmitter"; - Nikola Milutinovic
1
你在最后的代码片段中所做的与通过props将函数从父组件传递给其子组件有何不同? - GHOST-34

27

虽然回答可能有些晚了,但我想为任何可能会发现这个有用的人提供一些信息。

截至撰写此答案时(2020年7月),自React Native版本0.60.0+以来,它已经发生了很多变化,您可以使用EventEmitter的实例或静态地调用 DeviceEventEmitter方法。


以下是使用EventEmitter的一个示例:


import { EventEmitter } from 'events';

const newEvent = new EventEmitter();

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


使用DeviceEventEmitter的另一个示例:


import { DeviceEventEmitter } from 'react-native';

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

希望这对那些仍在寻找在React Native中实现自定义事件的方法的人有所帮助。


1
我喜欢这个DeviceEventEmitter,我不需要创建一个新实例。谢谢! - Noitidart
9
DeviceEventEmitter 对我来说运作良好,但仍然好奇为什么我在 React Native 文档中找不到它的说明。 - CharukaHS

1
我能够通过react-mixin找到一个解决方法。不确定它是否正确,但是它可以在不做任何修改的情况下工作。关键是在类定义后添加reactMixin(DetailView.prototype, Subscribable.Mixin);
参考EventEmitter和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);

0

我在 react-native 0.69.0 中是这样解决的:

import EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';

const emitter = new EventEmitter();

emitter.addListener('event name', (...args) => console.log('emitted with', args));
emitter.emit('event name', { message: 'Foo' });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接