3

I'm building an app in React Native using the React Navigation library. The issue I'm facing is that, when rendering a Tab Navigator inside of a Stack Navigator (HomeStack), each individual tab retains the header of the parent Stack Navigator, 'Home'.

After reading through the documentation on nesting navigators (https://reactnavigation.org/docs/nesting-navigators/), I've tried making each Tab within the Tab Navigator it's own Stack, removing the header on the parent Stack (using options={{headerShown: false}}), and setting the individual header title on each Tab Stack (using options={{ headerShown: true), but that simply removes the header entirely from each Tab.

The current flow is that the user opens up the app, is directed to the Sign In Stack, and then once they hit the 'Sign In' button, the application renders the HomeStack, which displays the various Tab options. However, every Tab has the same header 'Home', even though each tab is its own unique Stack.

Here is the current layout of my navigators (with an authentication context wrapped around everything):

//Home Screen (nested Tab Navigator)
function HomeScreen() {
  return (
    <Tab.Navigator >
      <Stack.Screen name="Profile" component={Profile}/>
      <Stack.Screen name="Goals" component={Goals}/>
      <Stack.Screen name="Board" component={Board}/>
      <Stack.Screen name="People" component={People}/>
    </Tab.Navigator>
  );

//Child Stacks (within Tab Navigator -- all follow same format)
function Profile() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Profile Screen</Text>
    </View>
  )
}

//Parent Navigation Container
return (
    <AuthContext.Provider value={authContext}>
      <NavigationContainer>
        <Stack.Navigator>
          {state.userToken == null ? (
            <Stack.Screen name="SignIn" component={SignInScreen} />
          ) : (
              <Stack.Screen name="Home" component={HomeScreen}/>
            )}
        </Stack.Navigator>
      </NavigationContainer >
    </AuthContext.Provider >
  );

This question has been asked previously, and the solution used to be adding an updated argument during initial Stack declaration (discussed here: https://github.com/react-navigation/react-navigation/issues/741), but the way that Navigators function has changed since the latest update (version 5). Now, adding arguments to your initial Stack declaration returns an error: enter image description here

The end goal of this is to have each Tab act as it's own Stack, and display a header with a unique title/action buttons in the top left/right corners of the screen. I'm still unclear how to accomplish this with the new changes, so any guidance would be appreciated!

Satchel Smidt
  • 65
  • 2
  • 7

1 Answers1

2
function getHeaderTitle(route) {
  const routeName = route.state
    ? route.state.routes[route.state.index].name
    : route.params?.screen || 'Profile';

  switch (routeName) {
    case 'Profile':
      return 'My profile';
    case 'Goals':
      return 'Goals';
    case 'Board':
      return 'Board';
    case 'People':
      return 'People';
  }
}

// ...

<Stack.Screen
  name="Home"
  component={HomeTabs}
  options={({ route }) => ({
    headerTitle: getHeaderTitle(route),
  })}
/>

https://reactnavigation.org/docs/screen-options-resolution#setting-parent-screen-options-based-on-child-navigators-state

satya164
  • 9,464
  • 2
  • 31
  • 42
  • Accessing the 'state' property of the 'route' object is not supported. If you want to get the focused route name, use the 'getFocusedRouteNameFromRoute' helper instead: https://reactnavigation.org/docs/screen-options-resolution/#setting-parent-screen-options-based-on-child-navigators-state – Nauman Moazzam Jul 07 '21 at 09:31