0

I am using the functional approach with react-navigation v5.0.0, and I have a stack-navigator which contains:

App.js

<Stack.Screen
   name="Profil"
   component={Profile}
   options={{
      headerStyle: {
         backgroundColor: '#2270b9'
      },
      headerTintColor: '#fff',
      headerTitleStyle: {
         color: 'white'
      },
      headerRight: () => (
         <View style={{ flex: 1, flexDirection: 'row' }}>
            <Ionicons
               style={{ color: 'white', marginRight: 15, marginTop: 5 }}
               size={32}
               onPress={() => { _sendMessage(...) }}            // <--- problem is here
               name="ios-mail"
               backgroundColor="#CCC"
            />
         </View>
      )
   }}
/>

Profile component looks roughly like this:

Profile.js

export default function Profile({ route, navigation }) {
   const { profile } = route.params;

   return (
      <SafeAreaView style={styles.container}>
         <View style={styles.container}>
            <ScrollView contentContainerStyle={styles.contentContainer}>
   [...]

Now the problem is, Profile gets initialized with a payload object ("profile"), when the profile is opened:

Search.js / Visitors.js

navigation.navigate('Profil', { profile });

And the issue is, the send-button which is added in App.js needs the profile object which is passed to the Profile.js as route param, but it is not available in App.js.

How can I thus create the header button within Profile component, so I can access the profile object?

2 Answers 2

1

You can try modifying your options prop to take route as parameter, like so:

options={({ route: { params: { profile } } }) => ({
  /** use profile here */
})

To put it in context of your App.js, note how options is a function taking { route } as parameter and returning your options object.

<Stack.Screen
   name="Profil"
   component={Profile}
   options={({ route: { params: { profile } } }) => ({ // <- Note that options in now a function
      headerStyle: {
         backgroundColor: '#2270b9'
      },
      headerTintColor: '#fff',
      headerTitleStyle: {
         color: 'white'
      },
      headerRight: () => (
         <View style={{ flex: 1, flexDirection: 'row' }}>
            <Ionicons
               style={{ color: 'white', marginRight: 15, marginTop: 5 }}
               size={32}
               onPress={() => { _sendMessage(profile) }} // <--- you can use profile here
               name="ios-mail"
               backgroundColor="#CCC"
            />
         </View>
      )
   })}
/>

react-navigation docs

Sign up to request clarification or add additional context in comments.

5 Comments

Unfortunately, the profile object is not known in App.js, where I construct the screens.
Have you tried it though? It does not need to be known in App.js, react navigation allows for constructing screen options based on params the screen receives when you navigate to it.
Ok you suggest to add that to component={Profile} in App.js? The profile object is needed in the onPress callback of the right header, how can I access it with yout snippet above?
I've updated the answer using your code snippet for context. options prop can be a function that takes { route, navigation } as parameter, giving you access to the profile object from route.params.
Ah, I get it now. Thanks for the clarification.
1

Actually, I found out to work around this - it can be resolved by adding the header within Profile.js (where the object is available) and not in App.js.

So I've just removed the code for the headerRight in App.js and instead put this in Profile.js:

export default function Profile({ route, navigation }) {
   const { profile } = route.params;

   React.useLayoutEffect(() => {
      navigation.setOptions({
         headerRight: () => (
            <View style={{ flex: 1, flexDirection: 'row' }}>
               <Ionicons
                  style={{ color: 'white', marginRight: 15, marginTop: 5 }}
                  size={32}
                  onPress={_onSendMessage}
                  name="ios-mail"
                  backgroundColor="#CCC"
                  enabled={ profile && profile.core ? true : false}
               />
            </View>
         )
      });
    }, []);

This way, no matter from where Profile.js is opened, the button callback will have access to the current profile object which is within Profile.js' state.

1 Comment

It's a valid solution. Small drawback, however, is that the button will appear only after the first render, which might not be what you want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.