Skip to content

Setting screen specific props / params #740

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

Closed
getnashty opened this issue Mar 20, 2017 · 20 comments
Closed

Setting screen specific props / params #740

getnashty opened this issue Mar 20, 2017 · 20 comments

Comments

@getnashty
Copy link

Is there a way to do this in the StackNavigator that I'm not seeing?

I would like to do something like:

const AuthFlows = StackNavigator({
  EnterInvite: {
    screen: EnterInvite,
    props: { ...myProps},
  }
});
@jbovenschen
Copy link

You can work around this with a helper factory function.

function createComponent(instance, props) {
  return () => React.createElement(instance, props);
}

const AuthFlows = StackNavigator({
  EnterInvite: {
    screen: createComponent(EnterInvite, myProps),
  }
});

I hope this helps.

@getnashty
Copy link
Author

Thanks @jbovenschen this seems to partially work - but that component doesn't seem to receive the navigation prop now. Any ideas?

@jbovenschen
Copy link

import merge from 'lodash/fp/merge'

function createComponent(instance, ownProps) {
  return (props) => React.createElement(instance, merge([ownProps, props], {});
}

This will give you the props derived from the higher order function / higher order component created with the createComponent also it works nearly the same as the createFactory function within react which will be removed in the future (Could not find the source of that...). Hope this helps :)

@satya164
Copy link
Member

satya164 commented Mar 21, 2017

Home: { screen: props => <Home {...props} {...myProps} /> }

@getnashty
Copy link
Author

thanks @jbovenschen & @satya164! - Satya's solution seems a little simpler, and is working for me so far - thanks again!

@scottbrassfield
Copy link

I was running into this same issue, and the answers above were really helpful!

Just as an FYI, when I wrapped my screen component in a function, as described above, my navigationOptions within the actual component (e.g., screen title) were not rendering. I set the navigationOptions within the navigator instead, and that solved the problem for me.

@JulianKingman
Copy link

Ditto, the static navigationOptions for the component seem to be ignored. @satya164 any idea how to use the component's navigationOptions?

@JulianKingman
Copy link

Ah, it has to do with hoisting the statics, but if I hoist the statics, (via hoist-non-react-statics), then the props are no longer passed. Here's what I have:

import hoist from 'hoist-non-react-statics';
const DrawerNavigator = RNDrawerNavigator({
  DisputeForm: {screen: hoist((props) => (<Link {...props} screenProps={{url: 'test.com'}}/>), Link)},
})

@JulianKingman
Copy link

Inspired by this comment (#235 (comment)), I did something like this:

const links = {
  ContactForm: {
    url: 'https://www.example.com/contact',
    label: 'Contact Us',
  },
  Blog: {
    url: 'https://blog.example.com',
    label: 'Blog',
  },
}
const DrawerNavigator = RNDrawerNavigator(
  {
    Home: {screen: TabNavigator},
    ContactForm: {screen: DrawerLink},
    Blog: {screen: DrawerLink},
  },
  {
    navigationOptions(props) {
      return {
        ...props.navigationOptions,
        links,
      };
    },
  },
);

// in DrawerLink.js
// CustomDrawerItem just renders a label and runs the onPress function
DrawerLink.navigationOptions = (props) => {
  const {navigation: {state: {routeName}}, navigationOptions, screenProps} = props;
  const {links} = navigationOptions;
  return {
    drawerLabel: ({tintColor, focused}) => {
      return (
        <CustomDrawerItem
          focused={focused}
          tintColor={tintColor}
          onPress={() => {
            WebBrowser.openBrowserAsync(
              links[routeName].url,
            );
          }}
          label={links[routeName].label}
        />
      );
    },
  };
};

@dzpt
Copy link

dzpt commented Aug 13, 2017

@satya164 It only works if Home is an React component. If Home is a StackNavigator, it gets:
simulator screen shot aug 13 2017 3 36 25 pm

@evanjmg
Copy link

evanjmg commented Oct 1, 2017

It should be dynamic and we shouldn't have to create smart components, have to use NavigatorIOS instead

@lolobosse
Copy link

lolobosse commented Dec 15, 2017

@JulianKingman I can reproduce the issue (that the navigationOption is being ignored) but I do not understand how you're fixing it (I mean I can see your code but I cannot really get what you're doing).

Can you provide a quick explanation? 🙏 😄

@JulianKingman
Copy link

AS mentioned above, it has to do with static hoisting. Static properties (duh as navigation options) do not get automatically hoisted.

Anyway, my solution is using navigationOptions as a function that returns the built in options (props.navigationOptions), along with my additional properties.

Does that answer your question?

@builtbyproxy
Copy link

builtbyproxy commented Jul 13, 2018

Chances are if you've followed any of the tutorials on the first page of google. youll have a structure like this:
image

Then you can either parse a screenProps={} to the Navigator on line 19, or parse props => <Profile {...props} style={{ 'gradientColors': ['#f7d1d6', '#FCFAFA'] }} /> to line 9 instead of just Profile as the value to the screen key.

Giving you something like this:
image

You can do either of these or both and they are received as youd expect with this.props.style.gradientColors in the case of line 9.

Sorry to dig up an old issue but this was the one that helped me so ill add this here since it seems the most 'findable' in a google search and no one has mentioned screenProps as a of the createStackNavigator itself.

@TomasGonzalez
Copy link

TomasGonzalez commented Aug 3, 2018

@JulianKingman

Ditto, the static navigationOptions for the component seem to be ignored. @satya164 any idea how to use the component's navigationOptions?

This is what I came up with.

class StackNavigator extends Component {
  render () {
      const Stack = createStackNavigator({
        EnterInvite: {
          screen: props => < EnterInvite {...props} {...this.props}/>,
          navigationOptions: EnterInvite.navigationOptions,
        },
      })
    return(<Stack/>)
  }
}


@rahulgi
Copy link

rahulgi commented Aug 9, 2018

A technique that I used to pass a defaultParam to a route:

const nav = createStackNavigator(
  {
    LoadingSplash: {
      screen: LoadingSplash,
      navigationOptions: ({ navigation }) => {
        if (!navigation.getParam("defaultRoute")) {
          navigation.setParams({ defaultRoute: RouteName.LogIn });
        }
        return {
          header: null
        };
      }
    },
    ...
  }
);

@PragyaTripathi
Copy link

ScreenProps are immutable once they are set and sent once, and therefore you cannot filter them out. Perhaps you can dispatch params once you have them available. This worked beautifully for me. Courtesy of perusing the docs: https://reactnavigation.org/docs/en/navigation-actions.html#setparams It even guarantees to change the state.

const setParamsActionLeaderboard = NavigationActions.setParams({
					params: { contract: this.props.contract, accountHash: accountHash },
					key: 'Leaderboard',
				});
this.props.navigation.dispatch(setParamsActionLeaderboard);

@joebernard
Copy link

Here is a working example of how to set navigationOptions when screens are passed as a function to a create*StackNavigator. When screens are passed as a variable it is not required. Not sure if this is a bug or just an artifact of not hoisting.

https://snack.expo.io/@joebernard/c3RhdG

@vetri-iteron
Copy link

vetri-iteron commented Jan 28, 2019

Hi @rahulgi ,

This is actually works for me. I used this method as follows,

LogOut: {
    navigationOptions: ({navigation}) => {
      if (navigation.getParam("isSignOut") != true) {
        navigation.setParams({ isSignOut: true });
      }
      return ({
      drawerLockMode: 'locked-open',
      drawerLabel: 'Sign out'
    })},
    screen: Login
  }

Inside the 'createDrawerNavigator'. Most people's solutions is not worked for me, But yours worked for me.

If anyone has any other ideas efficient than this, please suggest me.

Thanks.

@alangumer
Copy link

For params you can use the property params:

const AuthFlows = StackNavigator({
  EnterInvite: {
    screen: EnterInvite,
    params: {
        param1: value
    },
  }
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests