Skip to content

A collection of sample React Native Libraries that will show you how to use the New Architecture (Fabric & TurboModules) step-by-step.

License

Notifications You must be signed in to change notification settings

react-native-community/RNNewArchitectureLibraries

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 

Repository files navigation

RUN

This run starts from the feat/turbomodule-swift branch. Start from there up to the [TurboModule] Test the swift Turbomodule section. Then, follow the steps below to move your logic to a Swift implementation file.

This guide will teach how to implement a function call in the Native platform that produces a result in Javascript as an asynchronous event, instead of using a promise or a synchronous call. It also show how to set up properly the delegate pattern between Swift and Objective-C++, in case the Swift implementation needs some state.

Table of contents

Steps

  1. Open the calculator/src/NativeCalculator.js file and add the following lines
export interface Spec extends TurboModule {
    // your module methods go here, for example:
    add(a: number, b: number): Promise<number>;

+    // eventful Sqrt
+    eventfulSqrt(a: number): void;

+    addListener: (eventType: string) => void;
+    removeListeners: (count: number) => void;
}

Note: The addListener and removeListeners implementations will be provided by React Native.

Note: This will be fixed in the stable release of 0.71

  1. Open the calculator/ios/Calculator.swift file
  2. Add the following CalculatorDelegate protocol in it. This protocol will be implemented by the Objective-C++ class to provide the send event method to the Swift implementation
@objc protocol CalculatorDelegate {
    func sendEvent(name: String, result: Double)
}
  1. In the Calculator class, add a property to store the delegate (remember the weak keyword):
@objc class Calculator: NSObject {
+   @objc weak var delegate: CalculatorDelegate? = nil
// rest of the class
}
  1. Transform the static method into instance method
@objc class Calculator: NSObject {
    @objc weak var delegate: CalculatorDelegate? = nil

-    @objc static func add(a: Int, b: Int) -> Int {
+    @objc func add(a: Int, b: Int) -> Int {
        return a+b
    }
}
  1. Add the new method implementation:
@objc class Calculator: NSObject {
    @objc weak var delegate: CalculatorDelegate? = nil

    @objc func add(a: Int, b: Int) -> Int {
        return a+b
    }

+    @objc func eventfulSqrt(value: Double) {
+        delegate?.sendEvent(name: Event.sqrt.rawValue, result: sqrt(value));
+    }
}
  1. Add an extension for the supporting logic:
extension Calculator {
  // List of emittable events
  enum Event: String, CaseIterable {
    case sqrt
  }

  @objc
  static var supportedEvents: [String] {
    return Event.allCases.map(\.rawValue);
  }
}
  1. Open the header file calculator/ios/RNCalculator.h and make it extend RCTEventEmitter
#import <Foundation/Foundation.h>
+ #import <React/RCTEventEmitter.h>

#if RCT_NEW_ARCH_ENABLED

#import <RNCalculatorSpec/RNCalculatorSpec.h>
-@interface RNCalculator: NSObject <NativeCalculatorSpec>
+@interface RNCalculator: RCTEventEmitter <NativeCalculatorSpec>

#else

#import <React/RCTBridgeModule.h>
-@interface RNCalculator : NSObject <RCTBridgeModule>
+@interface RNCalculator : RCTEventEmitter <RCTBridgeModule>

#endif

@end
  1. Open the implementation file calculator/ios/RNCalculator.mm and:
    1. Make it conform to the protocol
    // Options 2.A - Conform to the protocol
    @interface RNCalculator () <CalculatorDelegate>
    @end
    1. Add a property to store the Calculator:
    @implementation RNCalculator {
        Calculator *calculator;
    }
    1. Implement the initializer, passing self as a delegate
    - (instancetype)init {
        self = [super init];
        if(self) {
            // Option 2.B - Instantiate the Calculator and set the delegate
            calculator = [Calculator new];
            calculator.delegate = self;
        }
        return self;
    }
    1. Given that we implemented a custom init, we need to implement the requiresMainQueueSetup method:
    + (BOOL)requiresMainQueueSetup {
        return NO;
    }
    1. Implement the RCTEventEmitter required fields. Notice that we leverage the Swift implementation
    - (NSArray<NSString *> *)supportedEvents {
        return [Calculator supportedEvents];
    }
    1. Implement the CalculatorDelegate requirements. Here we emit the event to the JS side of React Native. The sendEventWithName:body is provided by React Native itself.
    - (void)sendEventWithName:(NSString * _Nonnull)name result:(double)result {
        [self sendEventWithName:name body:@(result)];
    }
    1. Implement the Specs by calling the Swift code:
    RCT_EXPORT_METHOD(eventfulSqrt:(double)a)
    {
        [calculator eventfulSqrtWithValue:a];
    }
  1. from the NewArchitecture root app, run:
cd add ../calculator
cd ios
RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
cd ..
  1. Open the NewArchitecture/App.tsx file and, inside the function App() body:
    1. Add the following line to handle the new state
    const [sqrtState, setSqrtState] = useState<number | undefined>(undefined);
    1. Add a function to issue the computation:
    async function computeSqrt() {
        RNCalculator.eventfulSqrt(4);
    }
    1. Register to the event emitter:
    const eventEmitter = new NativeEventEmitter(RNCalculator);
    let subscription = null
    subscription = eventEmitter.addListener("sqrt", (event) => {
        setSqrtState(event);
    });
    1. Add the UI to test your code:
    <Text>eventfulSqrt(4)={sqrtState ? `${sqrtState}` : '???' } </Text>
    <Button title='Compute' onPress={computeSqrt}/>
  2. Run yarn ios from the NewArchitecture folder

Note: Not to pollute the repository, the code of the NewArchitecture app has not been pushed. Follow the previous guides to set it up:

About

A collection of sample React Native Libraries that will show you how to use the New Architecture (Fabric & TurboModules) step-by-step.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published