Home > Blockchain >  Reusing Stack with Group when nesting Navigation
Reusing Stack with Group when nesting Navigation

Time:03-30

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:

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"?

CodePudding user response:

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.

  • Related