Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native - call native Swift function that calls another function that triggers RCTEventEmiiter send event causes RCTCallableJSModules error

I have this Swift class, the function emitLogEvent calls RCTEventEmitter sendEvent which is being listened for in React Native. If I call this function directly from React, the sendEvent works and I can log out count from React Native.

import Foundation
import React

@objc(NativeGlobalEventEmitter)
class NativeGlobalEventEmitter: RCTEventEmitter {
  @objc
  func emitLogEvent() {
    sendEvent(withName: "globalEvent", body: ["count": 1])
  }
  
  override func supportedEvents() -> [String]! {
    return [
     "globalEvent"
    ]
   }
  
  override static func requiresMainQueueSetup() -> Bool {
    return true
  }
  
  override func constantsToExport() -> [AnyHashable : Any]! {
    return ["initialCount": 0]
  }
}

If I introduce another simple class with a function that calls emitLogEvent

import Foundation
@objc(TestMe)
class TestMe: NSObject {
   @objc
   func runTest() {
     print(200)
     let emitter = NativeGlobalEventEmitter()
     emitter.emitLogEvent();
   }
}

And then call runTest() from React Native, 200 is printed but I get the error

Exception 'Error when sending event: globalEvent with body: {
count = 1;
}. RCTCallableJSModules is not set. This is probably because you've explicitly 
synthesized the RCTCallableJSModules in NativeGlobalEventEmitter, even though it's 
inherited from RCTEventEmitter.' was thrown while invoking runTest on target TestMe 
with params (
)

Why would this be happening? I can call any of the functions directly and they work but calling a function that emits an event from another class causes the error

like image 829
Lecoda Avatar asked Oct 25 '25 11:10

Lecoda


1 Answers

I found the solution here

This issue with this is:

   func runTest() {
     print(200)
     let emitter = NativeGlobalEventEmitter()
     emitter.emitLogEvent();
   }

Instantiating an instance of NativeGlobalEventEmitter. This is because RN has already created the object and assigned it to the bridge.

Instead, override init() and set a property on the class

  public static var shared: NativeGlobalEventEmitter?
  
  override init() {
    super.init()
    NativeGlobalEventEmitter.shared = self
  }

You can then use it like this

   NativeGlobalEventEmitter.shared?.emitLogEvent()
like image 192
Lecoda Avatar answered Oct 27 '25 01:10

Lecoda