expo / ex-navigation

Route-centric navigation for React Native
997 stars 201 forks source link

how to access route props in the static route configuration? #235

Closed vonovak closed 7 years ago

vonovak commented 7 years ago

I'm navigating to a route and passing along a custom prop. I need to access the prop in the renderRight/Left function. Using the example from the docs:

static route = {
     navigationBar: {
       title: 'Title goes here',
       renderRight: (route, props) => <UseThePropsHere />
     }
   }

doesn't work for me - the props are an object with keys: {layout, navigationState, onNavigate, posiition, scene, scenes} but my object is not included. Are the docs up to date?

I have verified the prop is available in the component constructor.

thanks!

sibelius commented 7 years ago

How to communicate between navigationBar and your component?

You can use EventEmitter

class MyComp extends Component {
  static route = {
    navigationBar: {
      title: 'title',
      renderLeft: (state: ExNavigationState) => {
        const { config: { eventEmitter }  } = state;

        return (
          <TextMenuButton
            tintColor={state.getBarTintColor()}
            onPress={() => eventEmitter.emit('cancel')}
          >
            Cancel
          </TextMenuButton>
        )
      },
      renderRight: (state: ExNavigationState) => {
        const { config: { eventEmitter }  } = state;

        return (
          <TextMenuButton
            tintColor={state.getBarTintColor()}
            onPress={() => eventEmitter.emit('done')}
          >
            Done
          </TextMenuButton>
        );
      },
    },
    styles: {
      ...NavigationStyles.SlideVertical,
      gestures: null,
    },
  };

  _subscriptionDone: EventSubscription;
  _subscriptionCancel: EventSubscription;

  componentWillMount() {
    this._subscriptionDone = this.props.route.getEventEmitter().addListener('done', this._handleDone);
    this._subscriptionCancel = this.props.route.getEventEmitter().addListener('cancel', this._handleCancel);
  }

  componentWillUnmount() {
    this._subscriptionDone.remove();
    this._subscriptionCancel.remove();
  }

  _handleDone = () => {
    this.props.navigator.pop();
  }

  _handleCancel = () => {
    this.props.navigator.pop();
  }
}
vonovak commented 7 years ago

thanks, what I had in mind is actually mentioned in the docs, I was just being blind:

this.props.navigator.push(Router.getRoute('about', {name: 'Brent'}));
...
renderRight: ({params}, props) => <SignOutButton name={params.name}/>
Ali-Ayyad commented 7 years ago

@vonovak Hey there! What if i want to push into the stack another component ? For example i want to render a right button called Profile in the Navbar and on Press i want it to push into the stack.

vonovak commented 7 years ago

@Aloushiz in your button component you'd have

onPress: ({params}, props) => {
                props.navigator.push('FilterJobsScreen', {project: params.project})
            }

where params and props come from the same code as in my previous comment

vonovak commented 7 years ago

but you probably need to make sure that navigator gets passed through the props, or mark the button component as @ withNavigation and then the navigator will be in this.props.navigator

Ali-Ayyad commented 7 years ago

@vonovak i think you misunderstood my case, i have a tabBarNavigator and inside of each tabBarItem i have a StackNavigtion. In the first item i want to push another route but through a button i rendered in the navbar (static route)

<TabNavigator.Item selected={this.state.selectedTab === 'spots'} title="Spots" selectedTitleStyle={style_landing.selectedTitleStyle} renderIcon={() => <Image source={require('.././assets/images/spot.png')} /> } renderSelectedIcon={() => <Image source={require('.././assets/images/spot_pressed.png')} /> } onPress={() => this.setState({ selectedTab: 'spots' })}> <StackNavigation id="spots" navigatorUID="spots" initialRoute={Router.getRoute('spots', {navigator: this.props.navigator} )} /> </TabNavigator.Item>

` static route = { navigationBar: { visible: true, title:"", backgroundColor: Color.dark_grey, titleStyle:{color:Color.white}, renderRight: ({params}, props) => <TouchableOpacity onPress={()=>{}}

<Image source={require("../assets/images/profileLogo.png")}/> } } `

satya164 commented 7 years ago

@Aloushiz This doesn't work for you? https://github.com/exponentjs/ex-navigation/blob/master/example/components/EventEmitterExample.js

Ali-Ayyad commented 7 years ago

@satya164 It can work but i mean i'm sure there is a more appropriate way of doing it.

vonovak commented 7 years ago

@Aloushiz I'm also not a fan of event emitter. But I think I understood you question. I'd do

renderRight: ({params}, sceneRendererProps) => <ProfileButton params={params} srp={sceneRendererProps}/>`

and

@withNavigation
class ProfileButton extends Component {

gotoProfile=()=>{
    this.props.navigator.push('ProfileScreen')
}

render(){
<TouchableOpacity onPress={this.gotoProfile}>
...
</TouchableOpacity>
}
}
Ali-Ayyad commented 7 years ago

@vonovak Yup, this worked ! thanks a lot I was wondering @withNavigation gives the navigator according to where the component is used ?

vonovak commented 7 years ago

I hope it does :D I'm not using tabbed navigation

On Nov 18, 2016 6:45 PM, "Aloushiz" notifications@github.com wrote:

@vonovak https://github.com/vonovak Yup, this worked ! thanks a lot I was wondering @withNavigation gives the navigator according to where the component is used ?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/exponentjs/ex-navigation/issues/235#issuecomment-261594631, or mute the thread https://github.com/notifications/unsubscribe-auth/ABfmwz1e598TKA9DruqFT3uJTp7wktckks5q_eQ3gaJpZM4KuqtH .

JulianKingman commented 7 years ago

@sibelius Where does getBarTintColor() come from in your example? I've got the function working (per your example), but am not sure how to get values from the component into the route, such as I presume your getBarTintColor() would.

sibelius commented 7 years ago

check flow definitions: https://github.com/exponent/ex-navigation/blob/master/src/ExNavigationTypeDefinition.js.flow#L49

JulianKingman commented 7 years ago

Thanks for that. How do I use that to pass values through? I'm having trouble understanding what I'm seeing.

sibelius commented 7 years ago

try to add a console.log and try to understand the object

JulianKingman commented 7 years ago

I see, I assumed getBarTintColor() was being declared in the component somewhere, but I see now that it's part of the core code.

I was looking for this.props.navigator.updateCurrentRouteParams, then I can grab the params via the state parameter passed to the renderRight function.

devekoperiOS commented 7 years ago

@sibelius it works for me.

sibelius commented 7 years ago

added here: https://github.com/sibelius/ex-navigation-recipes/blob/master/recipes/NavBarCommunication.md

andrewkmin commented 7 years ago

Is it possible to dynamically change the NavBar Title? Example: Parent component: list of orders Child component: single order page (but I want the NavBar Title to be that specific order's #) Would appreciate help. Thanks.