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

[NavigationExperimental] Best way to dynamically change content of overlay from scene? #8350

Closed
joonhocho opened this issue Jun 23, 2016 · 7 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@joonhocho
Copy link
Contributor

joonhocho commented Jun 23, 2016

I want to control / update content of overlay from the scene component.
For example, I want to dynamically change nav bar title based on user interactions inside a scene without doing any navigation.

Afaik, the following is a simplified version of how scene and overlay are rendered inside a AnimatedView or CardStack.

<AnimatedView>
  {scene}
  {overlay}
</AnimatedView>

Correct me if I am wrong, but currently, it seems the only way to trigger rerendering of overlay from the scene is to update navigationState.
That means we need to use a reducer to create a new navigationState, which will cause rerendering of scene as well as overlay.
It sounds like an overkill and too heavy work for such a trivial task.

Another way I can think of is to expose a new API via context that can override overlayProps.
Here's a simplified code snippet for the concept:

class ContainerWithContext extends Component {
  getChildContext() {
    return {
      setOverlayProps: (overlayProps) => this.setState({overlayProps})
    };
  }
  renderOverlay() {
    return this.props.renderOverlay({
      ...this.props,
      ...this.state.overlayProps,
    });
  }
  render() {
    return (
      <View>
        {this.renderScene()}
        {this.renderOverlay()}
      </View>
    );
  }
}

const Overlay = ({title}) => <View><Text>{title}</Text></View>;

class Scene extends Component {
  static contextTypes = { setOverlayProps: PropTypes.func }

  updateNavTitle(title) {
    this.context.setOverlayProps(title);
  }
}

I can help with PR if you think this is a good idea.
What are your thoughts on this?

@jmurzy
Copy link
Contributor

jmurzy commented Jun 24, 2016

It would be overkill to use context here. There seems to be multiple ways to approach this. But I'm not convinced this belongs within NavigationExperimental. The low level nature of NavigationExperimental enables greater abstractions to be built up in higher layers.

Also, NavigationAnimatedView is deprecated. As for NavigationTransitioner, renderScene and renderOverlay are also deprecated. NavigationTransitioner now delegates the rendering of all its children to a user provided render function. This addresses the issue discussed here. A nice side effect of this is that it allows full control over both the scene and overlay components.

That means you can just pass in a ref (to your overlay) in props to your scenes and just call a function directly on your overlay component to mutate its internal state. Let me know if this doesn't make sense and I'll put together an example. Oh and then there is Redux 😆

🍺

@joonhocho
Copy link
Contributor Author

I've used Redux before, but haven't needed it yet since I started using Relay, but I think it's the time to use it together with Redux.

@chirag04
Copy link
Contributor

@joonhocho
Copy link
Contributor Author

I will close this as recommended solutions make sense.

@RichardLindhout
Copy link

RichardLindhout commented Jul 29, 2016

How can I make a reference to the header from my navRoot?

I have this now.

<NavigationCardStack onNavigateBack={this._handleBackAction.bind(this)} navigationState={this.props.navigation} onNavigate={this._handleNavigate.bind(this)} renderScene={this._renderScene} renderOverlay={this._renderHeader} />

` _renderHeader(props){
const { route } = props.scene

return (
  <Header
        route={route}

        _goBack={this._handleBackAction.bind(this)}
        _handleDrawerAction={this._handleDrawerAction.bind(this)}
        ref={(header) => { return this.header = header  }}>>
  </Header>

)
} `

When I try to do a function on the header from my navroot component
header.consoleLog()

I get an error in my application. this.headerconsoleLog is not a function.

Header component code snippets

` class Header extends Component {
constructor(props){
super(props)

this.consoleLog = this.consoleLog.bind(this)

}

consoleLog(){
console.log('Change header via other component');
} `

@RichardLindhout
Copy link

RichardLindhout commented Jul 29, 2016

@jmurzy What can I do to reference my header in e.g. my scenes?

I can't find examples for this. I need to send scrollY positions to my header component to do animation.

@Paul-Todd
Copy link

@jmurzy - I am still battling on how to change the overlay from a scene. What I would like to do is change the buttons and title from some of my view components created in the renderScene function.

Have you built the sample you mentioned above so we see how this is supposed to work?

@facebook facebook locked as resolved and limited conversation to collaborators Jul 10, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests

6 participants