React-native: [NavigatorIOS] doesn't update when passProps update

Created on 10 Apr 2015  Â·  33Comments  Â·  Source: facebook/react-native

I'm not sure if this is a feature or a bug:

When I change the value of passProps of a navigator, I expect it would re-render again, just like other react components do. However, it seems it will not do so.

For example,

          <NavigatorIOS
            style={{flex: 1}}
            initialRoute={{
              component: MyChatList,
              title: "My Chat List",
              passProps: {
                recentChats: this.state.ChatListData.recentChats,
                renderRow: this.renderRecentChat,
              },
            }} />

When the state ChatListData (which comes from flux) updates, the navigator will not update it self correspondly.

Locked

Most helpful comment

Yes. Please either remove it so people don't get confused or put a big red warning in the docs saying "this component breaks the underlying working of react". Wasted time until I found this bug.

All 33 comments

I don't know

initialRoute only specifies the initial scene in the navigator.

The reason we don't do this is we don't want to re-render all of the scenes every time you re-render NavigatorIOS. This would make the app very slow once you have several scenes open. If your props are changing, you can call navigator.replace(newRoute), or use event emitters to communicate to inner scenes.

Navigator handles this case a bit better. When you re-render, it will call renderScene again for the currently-visible scenes (unless you are mid-transition).

I'm still trying to figure out the ideal pattern for re-rendering internal scenes. Feedback and ideas are welcome!

@ericvicenti Oh, I totally forgot I can use replace. I feel that is a little anti-react though. I mean, monitoring new props ourself. On the other hand, using event emitters is probably more like Flux, right? However, I'd personally prefer keep the states on the top-most components and let it pass props down, instead of let the navigator listen to the store directly.

For the Navigator, would it also be slow if I keep re-render (new props keep coming, for example)?

Thanks for your elaborating.

I too ran into this when I first started writing a RN app.

Is there any way that calling setState can update props to any potential children on the same route like with React?

e.g.

  _buttonPress() {

    this.setState({
      input: 'heyo'
    })

  },

  render() {
    return (
      <View>
         <ChildComponent input={this.state.input} /> // input prop change will be heard by Child
      </View>
    )
  }

I understand that on mobile you're probably not building as complex UI Component structures for a given single route. I'm not sure what the benefits/trade-offs is/are here.

@mjw56, That code should work, the input prop would be updated when setState is called. Are you having difficulties when putting ChildComponent inside a Navigator or NavigatorIOS?

@lazywei, I agree that it would be nicer to re-render the scene when the NavigatorIOS gets re-rendered. It would be great if somebody could implement Navigator's renderScene API for NavigatorIOS. That way the initial route would remain, but you could re-render the scene according to changing state outside the navigator.

When it comes to slowness from re-rendering in Navigator, it shouldn't be a problem because Navigator is careful to only re-render scenes that are visible. This would also be important to do if somebody adds the renderScene API to NavigatorIOS.

You might run into issues if you want to re-render aggressively, but you could always improve the shouldComponentUpdate logic in your scenes.

It also doesn't update when navigationBarHidden is changed, see https://github.com/facebook/react-native/issues/846

Still an issue with React Native 0.6rc. Workaround is calling this.refs.navigator.replace(…) with the updated state in passProps.

may be this PR can solved your issue ?
https://github.com/facebook/react-native/pull/1733

@mars: It's a Workaround if you haven't got anything in NavigatorIOS. What if you have pushed several routes?

I am trying to use resetTo() in order to reset the whole thing every time new props come in. (http://stackoverflow.com/questions/31320583/invariant-violation-calling-pop-to-route-for-a-route-that-doesnt-exist)

Any idea?

@edo1493 I ended up using the more manual but less limiting React.Navigator and …navigator.immediatelyResetRouteStack(). See Navigator docs

@ericvicenti have you seen this? Thanks.

Thank you for reporting this issue and appreciate your patience. We've notified the core team for an update on this issue. We're looking for a response within the next 30 days or the issue may be closed.

Is this issue about Navigator or NavigatorIOS? I see references to both in here.

For clarification about the difference, check out @brentvatne's comparison

@ericvicenti this issue is w/ NavigatorIOS

Using the Navigator module instead re-renders routes/scenes at the appropriate times.

The issue is with NavigatorIOS.
Since I didn't have to re-render anything, I have solved with an EventEmitter that pass the updated props from componentWillReceiveProps.

Ok, that sounds like a reasonable workaround for now. We currently don't use NavigatorIOS at Fb, so its up to the community to get this one fixed.

@ericvicenti @vjeux @brentvatne this may sound crazy but should react native move NavigatorIOS out of core?

It can live in userland and will be better supported i guess if it's in userland.

Yes. Please either remove it so people don't get confused or put a big red warning in the docs saying "this component breaks the underlying working of react". Wasted time until I found this bug.

I know this is a bit off-topic, but is there a way to update the props of each component in the stackRoute of Navigator?

I am updating the state where Navigator is rendered, but the props don't seem to update. TabBar does this with StaticContainer, I am trying to find an Android workaround.

I think forceUpdate() just made my day. :smile:

Update: which doesn't seem to really work :cry:

I use v0.13.1.
I create getter method to get updated props, and pass to NavigatorIOS.
It is easy to keep the states on the top-most components and let it pass props down.
In this case there will be a problem?

For example,

  getRecentChats() {
    return this.state.ChatListData.recentChats;
  }
  render() {
    return (
      <NavigatorIOS
        style={{flex: 1}}
        initialRoute={{
          component: MyChatList,
          title: "My Chat List",
          passProps: {
            recentChats: getRecentChats.bind(this),
            renderRow: this.renderRecentChat,
          },
       }} />
    );
}

I've been using replacePreviousAndPop({}) for more complex pagination scenarios and it has worked fine, albeit less cache-y than I'd hoped.

@ericvicenti any idea why navigator.replace(newRoute) does't work in RN version 17 and 16? going back to version 14 now :(
replaceAtIndex method of NavigatorIOS seems to be identical.

It might be due to changes on the native side. I don't really work with NavigatorIOS, so I'm not sure

What happened with this? I'm also experiencing this error. Apparently we were going to see a response in 30 days but that was about 5 or 6 months ago.

+1

:+1:

+1

+1

Facebook don't support the native control (NavigatorIOS) - Navigator is their JS replacement and it works okay - try using that instead and it won't be full of bugs!

I'm using version 0.34.0 and Navigator (not NavigatorIOS) and I'm having this exact problem. State changes in my parent screens get passed into child/sibling screens via passProps, but the child/sibling screens don't get re-rendered. I have to call this.forceUpdate() on my child/sibling screens after calling back to the parent screen. It works fine, but it's not very "Reacty".

I am also experiencing the issue described by @Gagege, which is very easy to reproduce. It is counter intuitive because with all react components, you expect that props passed to a child will automatically re-render the child when they are updated in the parent via setState().

The use of Navigator's passProps functionality breaks this pattern and makes it difficult to update any view that is a child of a navigator.

I am going to try using NavigationExperimental to see if it has the same issue

This issue seems like it is now a bunch of different issues combined. @felipemullen I suggest trying ExNavigation and complaining to @skevy if it is not good enough, rather than NavigationExperimental which we are figuring out how to combine with ExNavigation soon. I'm going to close this issue, and I suggest if people continue to have similar problems they open a new issue and be very clear about whether the problem applies to Navigator or NavigatorIOS because they are pretty different in terms of getting them fixed.

Was this page helpful?
0 / 5 - 0 ratings