Module events
Event emitter declaration
To make it possible for the module to emit events, JS spec needs to declare 2 methods:
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
// ...
export interface Spec extends TurboModule {
addListener(eventName: string): void
removeListeners(count: number): void
}
export default TurboModuleRegistry.getEnforcing<Spec>('MyAwesomeModule');
Event emitter implementation in native code
- iOS
- Android
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface NativeMyAwesomeModule : RCTEventEmitter<RCTBridgeModule>
@end
#import "NativeMyAwesomeModule.h"
@implementation NativeMyAwesomeModule {
BOOL hasListeners;
}
RCT_EXPORT_MODULE(NativeMyAwesomeModule)
- (NSArray<NSString *> *)supportedEvents
{
return @[@"decentEvent", @"notGreatEvent"];
}
- (void)startObserving
{
hasListeners = YES;
}
- (void)stopObserving
{
hasListeners = NO;
}
- (void)onSomeNativeEvent:(NSString *)someNativeValue
{
if (hasListeners) {
[self sendEventWithName:@"decentEvent" body:@{ @"value": someNativeValue }];
}
}
@end
To enhance iOS native module with event emitting feature, it has to extend RCTEventEmitter
abstract class.
Then in the implementation part, module has to override supportedEvents
getter which declares names for events emitted by this module.
It has to also override startObserving
and stopObserving
methods, which are called when first and last listeners are added/removed.
To emit event, the module should call sendEventWithName:body:
method, which is inherited from RCTEventEmitter
class.
It takes event name and an object payload (NSDictionary type), which will be sent to JS listener.
- Kotlin
- Java
override fun addListener(eventName: String?) = Unit
override fun removeListeners(count: Double) = Unit
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactContext
import com.facebook.react.modules.core.DeviceEventManagerModule
// ...
fun onSomeNativeEvent(someNativeValue: String) {
val reactContext: ReactContext = getReactContextFromTheModule()
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
.emit("decentEvent", Arguments.createMap().apply {
putString("value", someNativeValue)
})
}
@Override
public void addListener(String eventName) {}
@Override
public void removeListeners(double count) {}
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
// ...
private void onSomeNativeEvent(String someNativeValue) {
ReactContext reactContext = getReactContextFromTheModule();
WritableMap payload = Arguments.createMap();
payload.putString("value", someNativeValue);
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("decentEvent", payload);
}
To enhance Android native module with event emitting feature, it has to:
- declare
addListener
andremoveListeners
methods - use
RCTDeviceEventEmitter
class for events emitting
To emit event, the module should call emit
method on RCTDeviceEventEmitter
instance.
The first argument is the event name and the second one is payload object (WritableMap
type) which will be sent to JS listener.
It can be constructed with Arguments.createMap
utility function.
Event emitter implementation in JS code
import { NativeEventEmitter, Platform } from 'react-native';
import { MyAwesomeModule } from 'my-awesome-module';
const moduleEventEmitter = new NativeEventEmitter(Platform.OS === 'ios' ? MyAwesomeModule : undefined);
// ...
useEffect(() => {
const subscription = moduleEventEmitter.addListener('decentEvent', ({ value }: { value: string }) => {
console.log({ someNativeValue: value });
});
return () => {
subscription.remove();
};
}, []);
To start listening to events emitted from native side, you have to:
- create
NativeEventEmitter
instance - invoke
addListener
method on that instance, providing the event name and the listener function
When the event is emitted, all listeners for that specific event will be called with the payload value.
When the listener is not needed, it should be removed - as a cleanup, it's recommended to invoke remove
method on the object returned from addListener
method call.
It will unregister provided listener from emitted native events.