React-native-navigation: Javascript gets executed twice

Created on 23 Apr 2019  路  8Comments  路  Source: wix/react-native-navigation

Issue Description

I noticed some really strange behaviour when using RNN in combination with react-native-splash-screen on iOS.
The Javascript Code of my current project gets executed twice when starting the app. That means, basically, I run into some very nasty race conditions (eg when making API calls) and unexpected behaviour while bootstrapping the app.

I tried to debug this issue and found out that it only occurs if the code in my AppDelegate.m is written in a specific order.
I also know that it has nothing to do with the JS Code itself. To proof that, I simply put a console.log('foo') into my index.js entry file and the code gets executed twice.

Did anyone stumble across this?

Steps to Reproduce / Code Snippets / Screenshots

normal behaviour

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];


  // putting RNSS first and RNN last will lead to normal behaviour.
  [RNSplashScreen show];
  [ReactNativeNavigation bootstrap:[self sourceURLForBridge: bridge] launchOptions:launchOptions];


  return YES;
}

abnormal behaviour

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];


  // putting RNN first and RNSS last will lead to normal behaviour.
  [ReactNativeNavigation bootstrap:[self sourceURLForBridge: bridge] launchOptions:launchOptions];
  [RNSplashScreen show];


  return YES;
}

Environment

  • React Native Navigation version: FILL THIS OUT
  • React Native version: 0.59.4
  • Platform(s) (iOS, Android, or both?): iOS
  • Device info (Simulator/Device? OS version? Debug/Release?): Sim + Device, iOS 12.2, Debug + Release
馃彋 stale

Most helpful comment

I am not quite sure why the execution order of RNN and RNS has an influence on this error but I guess I found the real root cause.

This is instantiating a bridge and executes the JS code and this snippet is provided by react native itself.

RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 

RNN seems to do the same thing but hidden inside its code. After some refactoring and deleting the react native method from above, everything works as expected now, no matter what execution order.

My AppDelegate.m now looks like this:

#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

#import <ReactNativeNavigation/ReactNativeNavigation.h>
#import <CodePush/CodePush.h>

#import <Fabric/Fabric.h>
#import <Crashlytics/Crashlytics.h>

#import "RNSplashScreen.h"



@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

  NSURL *jsCodeLocation;

  #if DEBUG
    jsCodeLocation =  [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
  #else
    jsCodeLocation = [CodePush bundleURL];
  #endif

  [ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];
  [Fabric with:@[[Crashlytics class]]];
  [RNSplashScreen show];

  return YES;
}

@end

My AppDelegate.h now looks like this:

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (nonatomic, strong) UIWindow *window;

@end

All 8 comments

I have a different problem; JS code is not executed at all, no matter the order. So SplashScreen.hide() is never called and I'm stuck on the launch screen.

My didFinishLaunchingWithOptions looks like this:

// React Native
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];

// React Native Splash Screen
[RNSplashScreen show];

// React Native Navigation
[ReactNativeNavigation bootstrap:[self sourceURLForBridge: bridge] launchOptions:launchOptions];

return YES;

@tizzyapunkt Have you gotten this to work with:

  • react-native: 0.59
  • react-native-navigation: 2.18.1
  • react-native-splash-screen: 3.2.0

    If so, using which order, and how/when are you calling SplashScreen.hide()?

@Dexwell
Currently I use the same order you use. I am calling SplashScreen.hide() in my bootstrapping process and it works like expected.

@tizzyapunkt So in Navigation.events().registerAppLaunchedListener()? And this is on react-native-navigation 2.18.1?

@Dexwell I am currently on 2.12.0 and the SplashScreen.hide() method gets fired somewhere else outside of this. Maybe you can just put your hide method somewhere else to see if it works in general

I am not quite sure why the execution order of RNN and RNS has an influence on this error but I guess I found the real root cause.

This is instantiating a bridge and executes the JS code and this snippet is provided by react native itself.

RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 

RNN seems to do the same thing but hidden inside its code. After some refactoring and deleting the react native method from above, everything works as expected now, no matter what execution order.

My AppDelegate.m now looks like this:

#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

#import <ReactNativeNavigation/ReactNativeNavigation.h>
#import <CodePush/CodePush.h>

#import <Fabric/Fabric.h>
#import <Crashlytics/Crashlytics.h>

#import "RNSplashScreen.h"



@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

  NSURL *jsCodeLocation;

  #if DEBUG
    jsCodeLocation =  [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
  #else
    jsCodeLocation = [CodePush bundleURL];
  #endif

  [ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];
  [Fabric with:@[[Crashlytics class]]];
  [RNSplashScreen show];

  return YES;
}

@end

My AppDelegate.h now looks like this:

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (nonatomic, strong) UIWindow *window;

@end

@tizzyapunkt Thank you, thank you, thank you! Finally got everything to work by removing the bridge part :D

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you believe the issue is still relevant, please test on the latest Detox and report back. Thank you for your contributions.

The issue has been closed for inactivity.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kiroukou picture kiroukou  路  3Comments

yedidyak picture yedidyak  路  3Comments

nbolender picture nbolender  路  3Comments

EliSadaka picture EliSadaka  路  3Comments

switchtrue picture switchtrue  路  3Comments