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.