• Stars
    star
    228
  • Rank 175,267 (Top 4 %)
  • Language
    Objective-C
  • License
    MIT License
  • Created about 9 years ago
  • Updated over 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A collection of examples for using React Native in an existing iOS application

React Native Hybrid App Examples

A collection of examples for using React Native in an existing iOS application

Concepts

Pre-loading the Bridge

One of the first things that you should do, if you want decent performance out of your hybrid app, is to pre-load your RCTBridge and keep a reference of it somewhere (possibly your AppDelegate):

AppDelegate.h

@property (nonatomic, strong) RCTBridge *bridge;

AppDelegate.m

@synthesize bridge;
...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ...configure the jsCodeLocation here...

    bridge = [[RCTBridge alloc] initWithBundleURL:jsCodeLocation
                                   moduleProvider:nil
                                    launchOptions:launchOptions];
                                    
    ...setup your rootViewController here...
    
    return YES;
}

This will allow the JavaScript to pre-load and allow you to use this bridge later on in other parts of the app:

AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:delegate.bridge moduleName:@"MyModule" initialProperties:nil];

Multiple "Entry" Points

In your index.ios.js file, you can "register" different modules that you want to use as seperate entry points in your app:

var React = require('react-native');
var {
  AppRegistry,
} = React;

var MainEntry = require('./Main');
var SecondEntry = require('./Second');
var ThirdEntry = require('./Third');

AppRegistry.registerComponent('MainEntry', () => MainEntry);
AppRegistry.registerComponent('SecondEntry', () => SecondEntry);
AppRegistry.registerComponent('ThirdEntry', () => ThirdEntry);

You can then pass these in as the moduleName when creating a RCTRootView:

RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:delegate.bridge moduleName:@"SecondEntry"];

Examples

Simple

  1. React View inside a Native View

    • Very basic example that shows how a React Native component can be loaded inside of a UIView that already exists in UIViewController.
  2. Passing Data into a React View

    • Demonstrates how you can use initialProperties on RCTRootView to pass data to your React Native component.

Advanced

  1. Native Modal With RN Navigation
    • This example demonstrates how a React Native component can communicate & perform actions on it's native Obj-C container.
    • Using a Coordinator native module, we are able to delegate method calls to the native Obj-C container.
      • Why don't we just export the methods directly on the Obj-C container itself? When a bridge is initialized, each native module gets instantiated and the bridge holds that instance. If we were to create another instance of that Obj-C container (from within our base Obj-C app), the JS calls wouldn't be able to use that instance, since it only knows about the instance on the bridge.
        • For this reason, we pass in a delegate to the native module instance on the bridge after the RCTBridge and RCTRootView are created.

        • For example:

          [(MyNativeModule *)[myAppdelegate.bridge.modules[@"MyNativeModule"] setDelegate:self]];
      • Why don't we use the moduleProvider block to pass in instances of the modules when the bridge loads? Since, we are trying to load the bridge at startup, for performance gains, we don't yet have the instance of all of our view controllers.
        • It's possible to do this (and perhaps recommended - no need for a Coordinator), but you would need to create your bridges when your container view controller loads, this could cause performance issues if you want your React Native components to display immediately.

        • For example (when loading your container view controller):

          RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:jsCodeLocation 
                                                moduleProvider:^ NSArray *{
                                                  return @[self];
                                                }
                                                 launchOptions:nil];
          
          RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName: @"MyModule"];
        • There is more discussion about this technique here.

Discussions About Hybrid Apps

Questions? Suggestions?

  • Are there a specific use-cases that you need a solution for? Is the documentation here a little confusing? Feel free to open up an issue.
  • Have you implemented something else than what's listed here? Can these examples be implemented in a better way? Please submit a pull request!