React-native-navigation: v2.15.0 Exception 'Component id already exists ... at setRoot on ios

Created on 23 Mar 2019  路  26Comments  路  Source: wix/react-native-navigation

Issue Description

I've just updated from RNN 2.7.1 to 2.15.0.

On Android, everything seems fine.

On iOS, I've got a crash at startup if I dare set any id to any component or stack in the setRoot call:

Navigation.setRoot({
    root: {
        sideMenu: {
            left: {
                component: {
                    // id: IDs.DRAWER,
                    name: MgxSideMenu,
                }
            },
            center: {
                stack: {
                    // id: IDs.MGX_STACK,
                    children: [{
                        component: {
                            name: MgxHome
                        },  
                    }],
                }
            },
        },
    }
});

If I uncomment any of those id attribute, it will crash at startup with: Exception 'Component id already exists blablabla...

Steps to Reproduce / Code Snippets / Screenshots

Set any id to any comp in your setRoot call and run on ios...


Environment

  • React Native Navigation version: 2.15.0
  • React Native version: 0.57.1
  • Platform(s) (iOS, Android, or both?): iOS
  • Device info (Simulator/Device? OS version? Debug/Release?): iPhone SE, debug
$ react-native info

  React Native Environment Info:
    System:
      OS: macOS High Sierra 10.13.6
      CPU: (4) x64 Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz
      Memory: 118.04 MB / 16.00 GB
      Shell: 3.2.57 - /bin/bash
    Binaries:
      Node: 8.11.3 - ~/.nvm/versions/node/v8.11.3/bin/node
      Yarn: 1.10.1 - /usr/local/bin/yarn
      npm: 5.6.0 - ~/.nvm/versions/node/v8.11.3/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
      Android SDK:
        API Levels: 18, 23, 24, 25, 26, 27, 28
        Build Tools: 23.0.1, 23.0.3, 25.0.0, 25.0.2, 25.0.3, 26.0.0, 26.0.1, 26.0.2, 26.0.3, 27.0.3, 28.0.3
        System Images: a... | Intel x86 Atom_64, a...gle_apis | Google APIs Intel x86 Atom_64 ...
    IDEs:
      Android Studio: 3.1 AI-173.4819257
      Xcode: 10.1/10B61 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.5.0 => 16.5.0 
      react-native: 0.57.1 => 0.57.1 
    npmGlobalPackages:
      react-native-app-id: 0.0.4
      react-native-cli: 2.0.1
      react-native-create-library: 3.1.2
iOS acceptebug

Most helpful comment

We're also seeing this on iOS after we upgraded to RN 0.59 and latest react-native-navigation together with react-native-splash-screen. If we disable the splash screen then everything works ok. Appreciate the work you've done with this library 馃槉

All 26 comments

Hey @zabojad, does this reproduce in the playground app?

@guyca I can't understand why but no, I am not able to reproduce it in the playground app even when editing the app.js as so:

Navigation.setRoot({
      root: {
        sideMenu: {
          left: {
            component: {
              id: 'left-drawer',
              name: Screens.SideMenuLeft
            }
          },
          center: {
            stack: {
              id: 'main-stack',
              children: [
                {
                  component: {
                    id: 'SideMenuCenter',
                    name: Screens.SideMenuCenter
                  }
                }
              ]
            }
          },
          right: {
            component: {
              id: 'right-menu',
              name: Screens.SideMenuRight,
            }
          }
        }
      }
    });

Here is my full error stacktrace:

2019-03-25 10:34:47.944 [fatal][tid:main] Exception 'Component id already exists myapp-stack' was thrown while invoking setRoot on target RNNBridgeModule with params (
    setRoot14,
        {
        modals =         (
        );
        overlays =         (
        );
        root =         {
            children =             (
                                {
                    children =                     (
                                                {
                            children =                             (
                            );
                            data =                             {
                                name = SideMenu;
                                options =                                 {
                                };
                            };
                            id = Component11;
                            type = Component;
                        }
                    );
                    data =                     {
                    };
                    id = SideMenuLeft10;
                    type = SideMenuLeft;
                },
                                {
                    children =                     (
                                                {
                            children =                             (
                                                                {
                                    children =                                     (
                                    );
                                    data =                                     {
                                        name = Home;
                                        options =                                         {
                                        };
                                    };
                                    id = Component13;
                                    type = Component;
                                }
                            );
                            data =                             {
                            };
                            id = "myapp-stack";
                            type = Stack;
                        }
                    );
                    data =                     {
                    };
                    id = SideMenuCenter12;
                    type = SideMenuCenter;
                }
            );
            data =             {
            };
            id = SideMenuRoot9;
            type = SideMenuRoot;
        };
    },
    216,
    217
)
callstack: (
    0   CoreFoundation                      0x00000001c1853f10 <redacted> + 252
    1   libobjc.A.dylib                     0x00000001c0a21a40 objc_exception_throw + 56
    2   MyApp                          0x0000000100ceaf04 -[RNNStore setComponent:componentId:] + 252
    3   MyApp                          0x0000000100cec634 -[RNNControllerFactory fromTree:] + 1252
    4   MyApp                          0x0000000100ced2e4 -[RNNControllerFactory createSideMenuChild:type:] + 216
    5   MyApp                          0x0000000100cec398 -[RNNControllerFactory fromTree:] + 584
    6   MyApp                          0x0000000100ced8f4 -[RNNControllerFactory extractChildrenViewControllersFromNode:] + 372
    7   MyApp                          0x0000000100ced154 -[RNNControllerFactory createSideMenu:] + 292
    8   MyApp                          0x0000000100cec33c -[RNNControllerFactory fromTree:] + 492
    9   MyApp                          0x0000000100cebea0 -[RNNControllerFactory createLayout:] + 72
    10  MyApp                          0x0000000100ce3ad4 -[RNNCommandsHandler setRoot:completion:] + 1436
    11  MyApp                          0x0000000100ca71c4 -[RNNBridgeModule setRoot:layout:resolver:rejecter:] + 312
    12  CoreFoundation                      0x00000001c185b660 <redacted> + 144
    13  CoreFoundation                      0x00000001c1737980 <redacted> + 292
    14  CoreFoundation                      0x00000001c1738564 <redacted> + 60
    15  MyApp                          0x0000000100d9a9d8 -[RCTModuleMethod invokeWithBridge:module:arguments:] + 2064
    16  MyApp                          0x0000000100e49dfc _ZN8facebook5reactL11invokeInnerEP9RCTBridgeP13RCTModuleDatajRKN5folly7dynamicE + 664
    17  MyApp                          0x0000000100e49980 _ZZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEiENK3$_0clEv + 132
    18  MyApp                          0x0000000100e498f0 ___ZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEi_block_invoke + 28
    19  libdispatch.dylib                   0x000000010182f840 _dispatch_call_block_and_release + 24
    20  libdispatch.dylib                   0x0000000101830de4 _dispatch_client_callout + 16
    21  libdispatch.dylib                   0x000000010183ea94 _dispatch_main_queue_callback_4CF + 1360
    22  CoreFoundation                      0x00000001c17e21bc <redacted> + 12
    23  CoreFoundation                      0x00000001c17dd084 <redacted> + 1964
    24  CoreFoundation                      0x00000001c17dc5b8 CFRunLoopRunSpecific + 436
    25  GraphicsServices                    0x00000001c3a50584 GSEventRunModal + 100
    26  UIKitCore                           0x00000001ee650bc8 UIApplicationMain + 212
    27  MyApp                          0x0000000100b92620 main + 124
    28  libdyld.dylib                       0x00000001c129cb94 <redacted> + 4
)

I'm clueless about this issue.

My Screen components are Reduxed and React Intled, could it be relevant in the debbugging of this issue?

I've tried previous RNN versions and here are my results:

  • 2.14.0 => same crash
  • 2.13.1 => same crash
  • 2.12.0 => same crash
  • 2.10.0 => same crash
  • 2.9.0 => OK, no crash
  • 2.8.0 => OK, no crash

So, it seems something happen between the 2.9.0 and the 2.10.0 that would cause this...

@guyca could you please help here? I don't know what to do more to finally solve this...

@yogevbd Seems like this regression was introduced by https://github.com/wix/react-native-navigation/commit/5abea28c53ed34dc822641f30abe2190c08f8185. Any ideas?

@zabojad Can you try await Navigation.setRoot()?

@yogevbd It doesn't work.

There is a messy "temporary" solution on js side. You should call the setRoot function twice. First-time calling has a fake stack id, then the second-time calling has the valid stack id and properties/values.

if (Platform.OS === 'ios') {
      try {
        Navigation.setRoot({
          root: {
            sideMenu: {
              center: {
                stack: {
                  id: 'TEMP',
                },
              },
            },
          },
        });
      } catch (error) {}
    }

    Navigation.setRoot({
      root: {
        sideMenu: {
          left: {
            component: {
              name: Screens.Drawer,
              id: Screens.Drawer,
            },
          },
          center: {
            stack: {
              id: 'STACK_ID',
              children: [
                {
                  component: {
                    name: screen
                  },
                },
              ],
            },
          },
        },
      },
    });

@yogevbd: If we call the setRoot function, we can remove all the components in the RNNStore. It works but I don't know the side effets.

RNNCommandsHandler.m:

 (void)setRoot:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
    [self assertReady];

    if (@available(iOS 9, *)) {
        if(_controllerFactory.defaultOptions.layout.direction.hasValue) {
            if ([_controllerFactory.defaultOptions.layout.direction.get isEqualToString:@"rtl"]) {
                [[RCTI18nUtil sharedInstance] allowRTL:YES];
                [[RCTI18nUtil sharedInstance] forceRTL:YES];
                [[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
                [[UINavigationBar appearance] setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
            } else {
                [[RCTI18nUtil sharedInstance] allowRTL:NO];
                [[RCTI18nUtil sharedInstance] forceRTL:NO];
                [[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
                [[UINavigationBar appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
            }
        }
    }

    [_modalManager dismissAllModalsAnimated:NO];
-   [_store removeAllComponentsFromWindow:_mainWindow];
+   [_store removeAllComponents];

    UIViewController<RNNLayoutProtocol> *vc = [_controllerFactory createLayout:layout[@"root"]];

    [vc renderTreeAndWait:[vc.resolveOptions.animations.setRoot.waitForRender getWithDefaultValue:NO] perform:^{
        _mainWindow.rootViewController = vc;
        [_eventEmitter sendOnNavigationCommandCompletion:setRoot params:@{@"layout": layout}];
        completion() ;
    }];
}

@guyca @yogevbd @eowo

OK, guys, thanks a lot for your help.

Please do not hate me but the problem came actually from my code. I did not realize it but my initialisation code was actually calling setRoot twice! I've fixed it in my app and everything is now rolling fine...

I do not know if setRoot should be allowed to be called more than once, but I'm actually quite happy that the RNN ios > 2.10.0 is actually complaining about this because I probably would not have spotted it anytime soon...

I let you decide what to do with this issue, close it or not.

Hey @zabojad
We realised that's the issue and that's why @yogevbd suggested to await the setRoot call. RNN shouldn't crash in the case, calling setRoot twice in quick succession is a valid use case (session becomes invalid before setRoot is completed for example).
We'll keep it open and fix asap.. 馃憤

We're also seeing this on iOS after we upgraded to RN 0.59 and latest react-native-navigation together with react-native-splash-screen. If we disable the splash screen then everything works ok. Appreciate the work you've done with this library 馃槉

We realised that's the issue and that's why @yogevbd suggested to await the setRoot call.

So in that case, await did not avoid the crash (I've tried it)...

I'm also getting this on iOS

@mayconmesquita Which version of RNN do you have? This should be resolved in 2.17.0

I was using v2.16.0. I will test the v2.17.0.
@guyca you really are doing a nice job here.

We have same issue in v2.17.0 and RN: v0.59.3

We are calling setRoot like this:

export default async function setupNavigation(tabs: object[]) {
  await Navigation.setRoot({
    root: {
      bottomTabs: {
        id: testID.NAVIGATION_ROOT_ID,
        children: tabs,
        options: { bottomTabs: { currentTabIndex: 2 }
      }
    }
  });
}

And function calling setupNavigation is located in index.js and looks like this:

async function onStoreUpdate() {
   // some logic here - removed for readability 
    await setupNavigation(generateMainMenu());
}

And finally caller of onStoreUpdate looks like this (also in index.js):

Navigation.events().registerAppLaunchedListener(async () => {
  // code removed for readability
  await onStoreUpdate();
});

Everything was working fine on RNN: v2.9.0 & RN v0.57.x

I'm facing this bug after updating from ^2.16.0 to ^2.17.0

Environment

  • React Native Navigation version: 2.17.0
  • React Native version: 0.59.3
  • Platform(s) (iOS, Android, or both?): IOS
  • Device info (Simulator/Device? OS version? Debug/Release?): Release, iPhone X

The same issue in 2.17.0

"react-native": "0.56.0"

I have the same issue with 2.12 with open debugger. I know I sometimes call setRoot twice in quick succession. Should I prevent it?

same here
"react-native": 0.57.5
"react-native-navigation": 2.16.0

using RNN 2.15 & RNSplashScreen & RN 0.59.4

got it working when I reverted the back the previous Appdelegate.m & Appdelegate.h files in iOS (RN 0.59 had changes in those)

Appdelegate.m

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import "AppDelegate.h"

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

#import "RNSplashScreen.h"

@implementation AppDelegate

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

#ifdef DEBUG
  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

#endif

  [ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];

  [RNSplashScreen show];

  return YES;
}

@end

Appdelegate.h
````
/**

  • Copyright (c) 2015-present, Facebook, Inc.
    *
  • This source code is licensed under the MIT license found in the
  • LICENSE file in the root directory of this source tree.
    */

import

@interface AppDelegate : UIResponder

@property (nonatomic, strong) UIWindow *window;

@end

I see the maintainers moved the issue to "DONE" card

where's the new commits ?
I'm having the same issue

@frodoe7 Try version 2.17.0-snapshot.283

@guyca , thanks it worked

but while building through XCode , I got this error

error: Build input file cannot be found:
'/Users/mohsen/Desktop/Shezlong/ShezlongTexting/node_modules/react-native-navigation/lib/ios/RNNStore.m'

and sometimes this one

error: Build input file cannot be found: '/Users/mohsen/Desktop/Shezlong/ShezlongTexting/node_modules/react-native-navigation/lib/ios/RNNLayoutManager.m'

cc @yogevbd

@frodoe7 I had the same issue with the missing RNNStore.m.
I fixed it by removing the ReactNativeNavigation.xcodeproj and adding it again.
As described in the documentation.
https://wix.github.io/react-native-navigation/#/docs/Installing?id=ios

@yavorsky how about if u remove prevRoot in setRoot function, in RNNCommandsHandler.m?
I think so

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SudoPlz picture SudoPlz  路  31Comments

mohdabbas picture mohdabbas  路  93Comments

yusufyildirim picture yusufyildirim  路  53Comments

Stalder picture Stalder  路  35Comments

diennguyentien picture diennguyentien  路  59Comments