React-Native中事件监听DeviceEventEmitter

基本语法

react-native中事件监听时使用插件DeviceEventEmitter这个来进行实现,在这里我们进行讲解一下基本语法,如下所示
1.设置监听
在想要接受监听的地方进行添加监听,假如是one.js页面

import { DeviceEventEmitter } from 'react-native';
...
componentDidMount() {
    //收到监听
    this.listener = DeviceEventEmitter.addListener('通知名称', (message) => {
    //收到监听后想做的事情
    console.log(message);  //监听
    })
}
componentWillUnmount() {
    //移除监听
    if (this.listener) {
      this.listener.remove();
    }
  }
...

从上面代码中,我们能够看到通过DeviceEventEmitter进行设置了监听,根据React生命周期,当组件加载的时候,我们进行监听,当组件卸载的时候,我们移除监听
2.触发监听
在我们需要触发one.js页面的监听的时候,我们能够在其他页面进行处罚,假定触发页面为two.js,则代码如下所示:

import { DeviceEventEmitter } from 'react-native';
...
startEmit() {
    //准备值,发监听
    const message = '监听';
    DeviceEventEmitter.emit('通知名称', message);
}
...

实例操作

在这里我们使用两个页面进行验证全局监听事件,在这里我们使用”react-navigation”(”1.5.12”),跳转界面,首先我们去实现第一个界面,在这个界面用于设置监听,代码如下所示:

import React, { Component } from 'react';
import { Button, Text, View, DeviceEventEmitter } from 'react-native';

class One extends Component {
  constructor(props) {
    super(props);
    this.state = { result: '我是默认值' };
  }
  componentDidMount() {
    // 收到监听
    this.listener = DeviceEventEmitter.addListener('changeResult', (message) => {
      // 收到监听后想做的事情 // 监听
      this.setState({ result: message });
    });
  }
  componentWillUnmount() {
    // 移除监听
    if (this.listener) { this.listener.remove(); }
  }

  _onChange = () => {
    const { navigation } = this.props;
    navigation.navigate('Two');
  };

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Button onPress={this._onChange} title="跳转到第二个页面" />
        <Text style={{ fontSize: 20, marginTop: 30 }}>{this.state.result}</Text>
      </View>
    );
  }
}
export default One;

之后我们完成第二个界面,在这个界面,我们进行对第一个界面监听事件的触发,代码如下所示:

import React, { Component } from 'react';
import { Button, View, DeviceEventEmitter } from 'react-native';
class Two extends Component {
  startEmit = () => {
    // 准备值,发监听
    const message = '监听发出通过,让one页面的值进行改变';
    DeviceEventEmitter.emit('changeResult', message);
  };

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Button onPress={this.startEmit} title="触发第一个页面的监听事件" />
      </View>
    );
  }
}
export default Two;

现在我们来看看具体的显示效果:



[emit]

源码说明

既然基本用法我们能够使用了,那么我们就找找看能不能看到源码信息,我们通过在one.js页面中点击(command+左键)DeviceEventEmitter插件,我们能够看到如下界面代码:



DeviceEventEmitter

在 // Plugins处我们能够看到这一行代码 get DeviceEventEmitter() { return require('RCTDeviceEventEmitter'); }, 也就是说我们DeviceEventEmitter在底层实现是RCTDeviceEventEmitter,那么我们就可以更加深入的查看下去,我们能够在Libaray文件夹中看到如下界面:


[emit]

之后找到RCTDeviceEventEmitter.js文件,如下代码,就是我从中复制的代码

/**
 * Deprecated - subclass NativeEventEmitter to create granular event modules instead of
 * adding all event listeners directly to RCTDeviceEventEmitter.
 */
class RCTDeviceEventEmitter extends EventEmitter {
  sharedSubscriber: EventSubscriptionVendor;
  constructor() {
    const sharedSubscriber = new EventSubscriptionVendor();
    super(sharedSubscriber);
    this.sharedSubscriber = sharedSubscriber;
  }
  addListener(eventType: string, listener: Function, context: ?Object): EmitterSubscription {
    if (__DEV__) {
      checkNativeEventModule(eventType);
    }
    return super.addListener(eventType, listener, context);
  }
  removeAllListeners(eventType: ?string) {
    if (__DEV__) {
      checkNativeEventModule(eventType);
    }
    super.removeAllListeners(eventType);
  }
  removeSubscription(subscription: EmitterSubscription) {
    if (subscription.emitter !== this) {
      subscription.emitter.removeSubscription(subscription);
    } else {
      super.removeSubscription(subscription);
    }
  }
}

module.exports = new RCTDeviceEventEmitter();

从代码中,我们能够看出实现了的方法有addListener,但是没有我们在使用中的其他方法,我们对代码进行分析,可以看到,在这里进行引入了下面这两个文件

const EventEmitter = require('EventEmitter');
const EventSubscriptionVendor = require('EventSubscriptionVendor');

于是我们能够看到如下界面:




能够看到我们需要的文件,打开EventEmitter.js文件,能够看到其实现代码了,内容如下所示:

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @providesModule EventEmitter
 * @noflow
 * @typecheck
 */
'use strict';

const EmitterSubscription = require('EmitterSubscription');
const EventSubscriptionVendor = require('EventSubscriptionVendor');

const emptyFunction = require('fbjs/lib/emptyFunction');
const invariant = require('fbjs/lib/invariant');

/**
 * @class EventEmitter
 * @description
 * An EventEmitter is responsible for managing a set of listeners and publishing
 * events to them when it is told that such events happened. In addition to the
 * data for the given event it also sends a event control object which allows
 * the listeners/handlers to prevent the default behavior of the given event.
 *
 * The emitter is designed to be generic enough to support all the different
 * contexts in which one might want to emit events. It is a simple multicast
 * mechanism on top of which extra functionality can be composed. For example, a
 * more advanced emitter may use an EventHolder and EventFactory.
 */
class EventEmitter {

  _subscriber: EventSubscriptionVendor;
  _currentSubscription: ?EmitterSubscription;

  /**
   * @constructor
   *
   * @param {EventSubscriptionVendor} subscriber - Optional subscriber instance
   *   to use. If omitted, a new subscriber will be created for the emitter.
   */
  constructor(subscriber: ?EventSubscriptionVendor) {
    this._subscriber = subscriber || new EventSubscriptionVendor();
  }

  /**
   * Adds a listener to be invoked when events of the specified type are
   * emitted. An optional calling context may be provided. The data arguments
   * emitted will be passed to the listener function.
   *
   * TODO: Annotate the listener arg's type. This is tricky because listeners
   *       can be invoked with varargs.
   *
   * @param {string} eventType - Name of the event to listen to
   * @param {function} listener - Function to invoke when the specified event is
   *   emitted
   * @param {*} context - Optional context object to use when invoking the
   *   listener
   */
  addListener(
    eventType: string, listener: Function, context: ?Object): EmitterSubscription {

    return (this._subscriber.addSubscription(
      eventType,
      new EmitterSubscription(this, this._subscriber, listener, context)
    ) : any);
  }

  /**
   * Similar to addListener, except that the listener is removed after it is
   * invoked once.
   *
   * @param {string} eventType - Name of the event to listen to
   * @param {function} listener - Function to invoke only once when the
   *   specified event is emitted
   * @param {*} context - Optional context object to use when invoking the
   *   listener
   */
  once(eventType: string, listener: Function, context: ?Object): EmitterSubscription {
    return this.addListener(eventType, (...args) => {
      this.removeCurrentListener();
      listener.apply(context, args);
    });
  }

  /**
   * Removes all of the registered listeners, including those registered as
   * listener maps.
   *
   * @param {?string} eventType - Optional name of the event whose registered
   *   listeners to remove
   */
  removeAllListeners(eventType: ?string) {
    this._subscriber.removeAllSubscriptions(eventType);
  }

  /**
   * Provides an API that can be called during an eventing cycle to remove the
   * last listener that was invoked. This allows a developer to provide an event
   * object that can remove the listener (or listener map) during the
   * invocation.
   *
   * If it is called when not inside of an emitting cycle it will throw.
   *
   * @throws {Error} When called not during an eventing cycle
   *
   * @example
   *   var subscription = emitter.addListenerMap({
   *     someEvent: function(data, event) {
   *       console.log(data);
   *       emitter.removeCurrentListener();
   *     }
   *   });
   *
   *   emitter.emit('someEvent', 'abc'); // logs 'abc'
   *   emitter.emit('someEvent', 'def'); // does not log anything
   */
  removeCurrentListener() {
    invariant(
      !!this._currentSubscription,
      'Not in an emitting cycle; there is no current subscription'
    );
    this.removeSubscription(this._currentSubscription);
  }

  /**
   * Removes a specific subscription. Called by the `remove()` method of the
   * subscription itself to ensure any necessary cleanup is performed.
   */
  removeSubscription(subscription: EmitterSubscription) {
    invariant(
      subscription.emitter === this,
      'Subscription does not belong to this emitter.'
    );
    this._subscriber.removeSubscription(subscription);
  }

  /**
   * Returns an array of listeners that are currently registered for the given
   * event.
   *
   * @param {string} eventType - Name of the event to query
   * @returns {array}
   */
  listeners(eventType: string): [EmitterSubscription] {
    const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any);
    return subscriptions
      ? subscriptions.filter(emptyFunction.thatReturnsTrue).map(
          function(subscription) {
            return subscription.listener;
          })
      : [];
  }

  /**
   * Emits an event of the given type with the given data. All handlers of that
   * particular type will be notified.
   *
   * @param {string} eventType - Name of the event to emit
   * @param {...*} Arbitrary arguments to be passed to each registered listener
   *
   * @example
   *   emitter.addListener('someEvent', function(message) {
   *     console.log(message);
   *   });
   *
   *   emitter.emit('someEvent', 'abc'); // logs 'abc'
   */
  emit(eventType: string) {
    const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any);
    if (subscriptions) {
      for (let i = 0, l = subscriptions.length; i < l; i++) {
        const subscription = subscriptions[i];

        // The subscription may have been removed during this event loop.
        if (subscription) {
          this._currentSubscription = subscription;
          subscription.listener.apply(
            subscription.context,
            Array.prototype.slice.call(arguments, 1)
          );
        }
      }
      this._currentSubscription = null;
    }
  }

  /**
   * Removes the given listener for event of specific type.
   *
   * @param {string} eventType - Name of the event to emit
   * @param {function} listener - Function to invoke when the specified event is
   *   emitted
   *
   * @example
   *   emitter.removeListener('someEvent', function(message) {
   *     console.log(message);
   *   }); // removes the listener if already registered
   *
   */
  removeListener(eventType: String, listener) {
    const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any);
    if (subscriptions) {
      for (let i = 0, l = subscriptions.length; i < l; i++) {
        const subscription = subscriptions[i];

        // The subscription may have been removed during this event loop.
        // its listener matches the listener in method parameters
        if (subscription && subscription.listener === listener) {
          subscription.remove();
        }
      }
    }
  }
}

module.exports = EventEmitter;

上述代码中,我们能够找到我们在one.js和two.js中使用的方法,如addListener通过传递字符串类型的事件类型,监听使用的方法和上下文进行添加订阅,如下所示:

  addListener(
    eventType: string, listener: Function, context: ?Object): EmitterSubscription {

    return (this._subscriber.addSubscription(
      eventType,
      new EmitterSubscription(this, this._subscriber, listener, context)
    ) : any);
  }

还有emit方法,通过事件类型,遍历所有的订阅事件进行获取指定eventType的subscriptions详细信息,然后通过apply方法将参数传递给上下文,如下所示代码:

  emit(eventType: string) {
    const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any);
    if (subscriptions) {
      for (let i = 0, l = subscriptions.length; i < l; i++) {
        const subscription = subscriptions[i];

        // The subscription may have been removed during this event loop.
        if (subscription) {
          this._currentSubscription = subscription;
          subscription.listener.apply(
            subscription.context,
            Array.prototype.slice.call(arguments, 1)
          );
        }
      }
      this._currentSubscription = null;
    }
  }

也就是我们发起请求时message信息的处理方式,在这过程中,当然还有其他几处代码进行了事件处理,在这里就不一一说明了


以上就是DeviceEventEmitter的使用

猜你喜欢

转载自blog.csdn.net/suwu150/article/details/81536432