Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to emit event in a Turbo Module on iOS

I'm following the guide here to create a Turbo Module in React Native. https://reactnative.dev/docs/next/the-new-architecture/pillars-turbomodules

How do you emit events on iOS? The documentation only shows how to call a native function from React, but not how to emit an event from the Turbo Module.

For Android, you get a ReactApplicationContext object, which lets you create an emitter like this using the context object.

private val emitter = context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
emitter.emit(eventName, eventArray)

How do you do the same thing on iOS?

like image 294
Berry Blue Avatar asked Oct 12 '25 04:10

Berry Blue


2 Answers

To emit events to RN from iOS you should make your own emitter class that is inherited from RCTEventEmitter and then init it on JS side with NativeEventEmitter and add listeners for needed events with addListener:

EventEmitter.h

#import <React/RCTEventEmitter.h>

@interface EventEmitter : RCTEventEmitter

+ (instancetype)shared;

@end

EventEmitter.m

#import "EventEmitter.h"

// Events
static NSString* onMyEvent = @"onMyEvent";

// Variable to save the instance
static EventEmitter* eventEmitter = nil;

@implementation EventEmitter

/// Exposing "EventEmitter" name to RN
RCT_EXPORT_MODULE(EventEmitter);

// Called from RN
- (instancetype)init {
  if (self = [super init]) {
    eventEmitter = self;
  }
  return self;
}

+ (BOOL)requiresMainQueueSetup {
    return NO;
}

+ (instancetype)shared {
  return eventEmitter;
}

// List of supported events
- (NSArray<NSString *> *)supportedEvents {
  return @[onMyEvent];
}

@end

How to call:

NSDictionary* body = @{@"message" : @"Hello Emitter!"};
[EventEmitter.shared sendEventWithName:@"onMyEvent" body:body];

RN/JS


import {
  ...
  NativeEventEmitter,
  NativeModules,
} from 'react-native';
import type EmitterSubscription from 'react-native';

class EventHandler extends React.Component {
  eventsSubscription: EmitterSubscription;

  componentDidMount() {
    const eventEmitter = new NativeEventEmitter(NativeModules.EventEmitter);

    this.eventsSubscription = eventEmitter.addListener('onMyEvent', event => {
      console.log(event.message); // Prints "Hello Emitter!"
    });
  }

  componentWillUnmount() {
    this.eventsSubscription.remove();
  }

  ...
};
like image 152
iUrii Avatar answered Oct 14 '25 18:10

iUrii


In my case, the accepted answer was not enough to make it work.

This tutorial (part of React Native community organisation) on the branch feat/swift-event-emitter helped me to make it works: https://github.com/react-native-community/RNNewArchitectureLibraries/tree/feat/swift-event-emitter

Particularly these lines that were missing in my JSI spec:

    addListener: (eventType: string) => void;
    removeListeners: (count: number) => void;
like image 23
OlivierM Avatar answered Oct 14 '25 20:10

OlivierM