Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Reusing Stack with Group when nesting Navigation

Using React Navigation 6, in the documentation, they recommend you use Groups to minimize nested navigators.

However I’m not sure how to do that in this example, using a nested Stack in a Tab Navigator:

import * as React from 'react';
import { View, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function FeedScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        title="Go to Settings"
        onPress={() => navigation.navigate('Settings')}
      />
    </View>
  );
}

function ProfileScreen() {
  return <View />;
}

function SettingsScreen() {
  return <View />;
}

const FeedStack = createNativeStackNavigator();

function FeedStackScreen() {
  return (
    <FeedStack.Navigator>
      <FeedStack.Screen name="Feed" component={FeedScreen} />
      {/* other screens */}
    </FeedStack.Navigator>
  );
}

const ProfileStack = createNativeStackNavigator();

function ProfileStackScreen() {
  return (
    <ProfileStack.Navigator>
      <ProfileStack.Screen name="Profile" component={ProfileScreen} />
      {/* other screens */}
    </ProfileStack.Navigator>
  );
}

const Tab = createBottomTabNavigator();

function HomeTabs() {
  return (
    <Tab.Navigator screenOptions={{headerShown: false}}>
      <Tab.Screen name="Feed" component={FeedStackScreen} />
      <Tab.Screen name="Profile" component={ProfileStackScreen} />
    </Tab.Navigator>
  );
}

const RootStack = createNativeStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <RootStack.Navigator>
        <RootStack.Screen
          name="Home"
          component={HomeTabs}
          options={{ headerShown: false }}
        />
        <RootStack.Screen name="Settings" component={SettingsScreen} />
      </RootStack.Navigator>
    </NavigationContainer>
  );
}

When I reuse the Stack so only one is used in the Tab Navigator it still works:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

const TabStack = createNativeStackNavigator();

function FeedStackScreen() {
  return (
    <TabStack.Navigator>
      <TabStack.Screen name="Feed" component={FeedScreen} />
      {/* other screens */}
    </TabStack.Navigator>
  );
}

function ProfileStackScreen() {
  return (
    <TabStack.Navigator>
      <TabStack.Screen name="Profile" component={ProfileScreen} />
      {/* other screens */}
    </TabStack.Navigator>
  );
}

const Tab = createBottomTabNavigator();

function HomeTabs() {
  return (
    <Tab.Navigator screenOptions={{headerShown: false}}>
      <Tab.Screen name="Feed" component={FeedStackScreen} />
      <Tab.Screen name="Profile" component={ProfileStackScreen} />
    </Tab.Navigator>
  );
}

However when I try to use Group like this:

const TabStack = createNativeStackNavigator();

function FeedStackScreen() {
  return (
    <TabStack.Group>
      <TabStack.Screen name="Feed" component={FeedScreen} />
      {/* other screens */}
    </TabStack.Group>
  );
}

function ProfileStackScreen() {
  return (
    <TabStack.Group>
      <TabStack.Screen name="Profile" component={ProfileScreen} />
      {/* other screens */}
    </TabStack.Group>
  );
}

const Tab = createBottomTabNavigator();

function HomeTabs() {
  return (
    <Tab.Navigator screenOptions={{headerShown: false}}>
      <TabStack.Navigator>
        <Tab.Screen name="Feed" component={FeedStackScreen} />
        <Tab.Screen name="Profile" component={ProfileStackScreen} />
      </TabStack.Navigator>
    </Tab.Navigator>
  );
}

I get the error a navigator can only contain 'screen' 'group' or 'react.fragment' because you can’t have a navigator inside another without writing it in the component.

Is there a way to use Group here or is the correct way to write <TabStack.Navigator></TabStack.Navigator> for each of the "Groups"?

>Solution :

The problem here is that Group is a component returned by the navigator. If we create a JSX component that returns that group instead, then this is technically not a Group anymore but its own JSX component.

This is an unsolved problem in react-native-navigation and is discussed in this GitHub issue, but has apparently no satisfying solution other than an ugly hack.

We can call the functional component inline.

function CustomGroupComponent() {
  return <Tab.Group>
          <Tab.Screen ... />
          <Tab.Screen ... />
      </Tab.Group>
}

export const Tabs = (props) => {

  return (

     <Tab.Navigator ...>
         <Tab.Screen ...>
         {CustomGroupComponent()}
     </Tab.Navigator>
  )
}

Thus in summary, there is no pretty solution. The trick is to call the functional component as a function inline using {CustomGroupComponet()}.

Remarks: I would consider this as an anti-pattern, but there is no other solution in the current version as far as I am concerned.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading