Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RCTRootView: updating appProperties does not work on iOS if bridge is still loading #20115

Closed
teameh opened this Issue Jul 9, 2018 · 6 comments

Comments

Projects
None yet
6 participants
@teameh
Copy link
Contributor

teameh commented Jul 9, 2018

Environment

Scanning folders for symlinks in /Users/veen011/Projects/Apps/AppPropertiesNoReRenderWhileBridgeIsLoading/node_modules (13ms)

  React Native Environment Info:
    System:
      ### Please let me know if you need this ###
    Binaries:
      Node: 10.5.0 - /usr/local/bin/node
      Yarn: 1.7.0 - /usr/local/bin/yarn
      npm: 6.1.0 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 11.4, macOS 10.13, tvOS 11.4, watchOS 4.3
    IDEs:
      Android Studio: 3.1 AI-173.4819257
      Xcode: 9.4.1/9F2000 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.4.1 => 16.4.1
      react-native: 0.56.0 => 0.56.0

Short description

Follow up on #15938

Relevant documentation:

RCTRootView also provides a read-write property appProperties. After appProperties is set, the React Native app is re-rendered with new properties. The update is only performed when the new updated properties differ from the previous ones.
{...}
It is fine to update properties anytime. However, updates have to be performed on the main thread. You use the getter on any thread.

This is not the case, the app is not re-rendered if the bridge was still loading when the properties are updated.

Reproducible Demo

git clone git@github.com:teameh/AppPropertiesNoReRenderWhileBridgeIsLoading.git
cd AppPropertiesNoReRenderWhileBridgeIsLoading
react-native run-ios

or

The only change I made to the sample project is adding and updating some some props of the view:

    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                       moduleName:@"AppPropertiesNoReRenderWhileBridgeIsLoading"
-                                               initialProperties:nil
+                                               initialProperties:@{@"foo" : @"bar"}
                                                    launchOptions:launchOptions];
+
+  rootView.appProperties = @{@"foo" : @"qux"};

Which are used in the RN view:

<Text style={styles.welcome}>"{this.props.foo}"</Text>

Before reloading the project the 3rd text node on the view should display "qux" if it displays "bar" it means the props have not been updated.

bar-qux

@teameh

This comment has been minimized.

Copy link
Contributor Author

teameh commented Jul 9, 2018

I did some more digging and I think this is caused by the following:

  • In RCTRootView's initWithBridge method bundleFinishedLoading is always called even though the javascript might still be loading..

  • bundleFinishedLoading calls runApplication:bridge with the initial properties.

  • An instant later, when setAppProperties is called (and normally the app runs again) the bridge is still loading so the app won't run again:

- (void)setAppProperties:(NSDictionary *)appProperties
{
  RCTAssertMainQueue();

  if ([_appProperties isEqualToDictionary:appProperties]) {
    return;
  }

  _appProperties = [appProperties copy];

  if (_contentView && _bridge.valid && !_bridge.loading) {
    [self runApplication:_bridge];
  }
}
- (void)javaScriptDidLoad:(NSNotification *)notification
{
  RCTAssertMainQueue();

  // Use the (batched) bridge that's sent in the notification payload, so the
  // RCTRootContentView is scoped to the right bridge
  RCTBridge *bridge = notification.userInfo[@"bridge"];
  if (bridge != _contentView.bridge) {
    [self bundleFinishedLoading:bridge];
  }
}
@teameh

This comment has been minimized.

Copy link
Contributor Author

teameh commented Jul 9, 2018

Tried to write some code that fixes this, see the PR.

@teameh

This comment has been minimized.

Copy link
Contributor Author

teameh commented Jul 26, 2018

Is there anything I can do to help fix this issue? No worries, I understand that it's hard to maintain a repo with 600+ open issues :)

@jessedijkstra

This comment has been minimized.

Copy link

jessedijkstra commented Aug 24, 2018

I'm having the same issue, any updates?

@harking

This comment has been minimized.

Copy link

harking commented Nov 8, 2018

Until this is fixed, a workaround is to listen to the RCTJavaScriptDidLoad and set the appProperties in there.

NotificationCenter.default.addObserver(forName: NSNotification.Name.RCTJavaScriptDidLoad, object: nil, queue: nil) {
    [weak self] _ in
    self?.setAppProperties()
}
@jessedijkstra

This comment has been minimized.

Copy link

jessedijkstra commented Feb 25, 2019

@cpojer The issue has been closed, does that mean that this bug has been fixed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.