Document subclassing RCTEventEmitter

Summary:
Sending global events with `eventDispatcher` has been [deprecated](d9737571c4) since 0.28, with a recommendation to subclass `RCTEventEmitter` instead, but there were no docs for this.

This updates the iOS native module to use the recommended way, and also documents the use of `stopObserving` and `startObserving`.

Tested and working in a real app.

cc nicklockwood
Closes https://github.com/facebook/react-native/pull/11792

Differential Revision: D4394626

fbshipit-source-id: 68b26d35944a521bf683a50ec1ab21f03b5e99d8
This commit is contained in:
Rob Hogan 2017-01-09 14:30:40 -08:00 committed by Facebook Github Bot
parent 7ca5316562
commit 8729d27206
1 changed files with 55 additions and 9 deletions

View File

@ -336,32 +336,49 @@ Your enum will then be automatically unwrapped using the selector provided (`int
## Sending Events to JavaScript
The native module can signal events to JavaScript without being invoked directly. The easiest way to do this is to use `eventDispatcher`:
The native module can signal events to JavaScript without being invoked directly. The preferred way to do this is to subclass `RCTEventEmitter`, implement `suppportEvents` and call `self sendEventWithName`:
```objective-c
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
// CalendarManager.h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface CalendarManager : RCTEventEmitter <RCTBridgeModule>
@end
```
```objective-c
// CalendarManager.m
#import "CalendarManager.h"
@implementation CalendarManager
@synthesize bridge = _bridge;
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents
{
return @[@"EventReminder"];
}
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
NSString *eventName = notification.userInfo[@"name"];
[self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder"
body:@{@"name": eventName}];
[self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
}
@end
```
JavaScript code can subscribe to these events:
JavaScript code can subscribe to these events by creating a new `NativeEventEmitter` instance around your module.
```javascript
import { NativeAppEventEmitter } from 'react-native';
import { NativeEventEmitter, NativeModules } from 'react-native';
const { CalendarManager } = NativeModules;
var subscription = NativeAppEventEmitter.addListener(
const calendarManagerEmitter = new NativeEventEmitter(CalendarManager);
const subscription = calendarManagerEmitter.addListener(
'EventReminder',
(reminder) => console.log(reminder.name)
);
@ -371,6 +388,35 @@ subscription.remove();
```
For more examples of sending events to JavaScript, see [`RCTLocationObserver`](https://github.com/facebook/react-native/blob/master/Libraries/Geolocation/RCTLocationObserver.m).
### Optimizing for zero listeners
You will receive a warning if you expend resources unnecessarily by emitting an event while there are no listeners. To avoid this, and to optimize your module's workload (e.g. by unsubscribing from upstream notifications or pausing background tasks), you can override `startObserving` and `stopObserving` in your `RCTEventEmitter` subclass.
```objective-c
@implementation CalendarManager
{
bool hasListeners;
}
// Will be called when this module's first listener is added.
-(void)startObserving {
hasListeners = YES;
// Set up any upstream listeners or background tasks as necessary
}
// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
hasListeners = NO;
// Remove upstream listeners, stop unnecessary background tasks
}
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
NSString *eventName = notification.userInfo[@"name"];
if (hasListeners) { // Only send events if anyone is listening
[self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
}
}
```
## Exporting Swift
Swift doesn't have support for macros so exposing it to React Native requires a bit more setup but works relatively the same.