Reputation: 21
I've found a solution. Posting in here very soon...
I built my project with React-Native with Expo SDK 49 while using Expo-Router V2 for my routes.
I'd like to have a Stack Route inside my Home screen, which is a Tab Screen. But for some reason only the new Stack Screen is being rendered once I navigate to Home.
OBS: All my routes folders have: index.tsx, _layout.tsx and a components folder
src
|-(app) // Both root Stack screens are working. They have: index.tsx & _layout.tsx
|-(login) // Stack Screen
|-...
|-(signup) // Stack Screen
|-...
|-(tabs)
|-(history)
|-...
|-(home)
|-(exercise_details)
|-components
|-_layout.tsx
|-index.tsx
|-(profile)
|-...
|-_layout.tsx
import { Slot } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { ExerciseProvider } from "@/contexts/ExerciseContext";
import { NativeBaseProvider, Box, Center } from "native-base";
import { AppLoader } from "@/components/AppLoader";
import { THEME } from "@/theme";
import {
useFonts,
Roboto_400Regular,
Roboto_700Bold,
} from "@expo-google-fonts/roboto";
export default function RootLayout() {
const [fontsLoaded] = useFonts({ Roboto_400Regular, Roboto_700Bold });
const AppIsBuilding = () => {
return (
<Center flexGrow={1} bg="gray.700">
<AppLoader size="lg" />
</Center>
);
};
const AppContent = () => {
return (
<Box flex={1} bg="gray.700">
<ExerciseProvider>
<Slot />
</ExerciseProvider>
<StatusBar
animated
translucent
style="light"
backgroundColor="transparent"
/>
</Box>
);
};
return (
<>
<NativeBaseProvider theme={THEME}>
{fontsLoaded ? <AppContent /> : <AppIsBuilding />}
</NativeBaseProvider>
</>
);
}
import { Tabs } from "expo-router";
import {
House,
UserCircle,
ClockCounterClockwise,
} from "phosphor-react-native";
import { THEME } from "@/theme";
export default function TabsLayout() {
return (
<Tabs
initialRouteName="(home)"
screenOptions={{
tabBarStyle: {
height: 75,
backgroundColor: THEME.colors.gray[600],
borderColor: THEME.colors.gray[600],
},
tabBarActiveTintColor: THEME.colors.green[500],
tabBarInactiveTintColor: THEME.colors.gray[300],
}}
>
<Tabs.Screen
name="(home)"
options={{
title: "",
headerShown: false,
tabBarIcon: ({ size, color }) => (
<House
size={size}
color={color}
weight={color === THEME.colors.green[500] ? "bold" : "regular"}
/>
),
}}
/>
<Tabs.Screen
name="(history)"
options={{
title: "",
headerShown: false,
tabBarIcon: ({ size, color }) => (
<ClockCounterClockwise
size={size}
color={color}
weight={color === THEME.colors.green[500] ? "bold" : "regular"}
/>
),
}}
/>
<Tabs.Screen
name="(profile)"
options={{
title: "",
headerShown: false,
tabBarIcon: ({ size, color }) => (
<UserCircle
size={size}
color={color}
weight={color === THEME.colors.green[500] ? "bold" : "regular"}
/>
),
}}
/>
</Tabs>
);
}
import { router, Slot, Tabs } from "expo-router";
import { TouchableOpacity } from "react-native";
import { MaterialIcons } from "@expo/vector-icons";
import { HStack, VStack, Text, Icon, Heading } from "native-base";
import { AppUserPicture } from "@/components/AppUserPicture";
export default function HomeLayout() {
function handleGoBack() {
router.canGoBack() && router.back();
}
return (
<>
<Tabs.Screen
options={{
headerShown: true,
header: () => (
<HStack
bg="gray.600"
padding={6}
height={117}
alignItems="center"
justifyContent="space-between"
safeArea
>
<AppUserPicture w={50} h={50} />
<VStack flex={1} ml={4}>
<Text color="gray.100" fontSize="md">
Olá,
</Text>
<Heading color="gray.100" fontSize="md">
Alan Graton
</Heading>
</VStack>
<TouchableOpacity onPress={handleGoBack}>
<Icon
as={MaterialIcons}
name="logout"
color="gray.200"
size={6}
/>
</TouchableOpacity>
</HStack>
),
}}
/>
</>
);
}
import { Slot, Stack } from "expo-router";
export default function ExerciseDetailsLayout() {
return (
<Stack initialRouteName="(home)" screenOptions={{ headerShown: false }} />
);
}
I already tried doing something like so:
import { Stack } from 'expo-router';
export default function RootLayout() {
const [fontsLoaded] = useFonts({ Roboto_400Regular, Roboto_700Bold });
const AppIsBuilding = () => {
return (
<Center flexGrow={1} bg="gray.700">
<AppLoader size="lg" />
</Center>
);
};
const AppContent = () => {
return (
<Box flex={1} bg="gray.700">
<ExerciseProvider>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="(tabs)" />
</Stack>
</ExerciseProvider>
<StatusBar
animated
translucent
style="light"
backgroundColor="transparent"
/>
</Box>
);
};
return (
<>
<NativeBaseProvider theme={THEME}>
{fontsLoaded ? <AppContent /> : <AppIsBuilding />}
</NativeBaseProvider>
</>
);
}
But it just returned the same result ;-;
Also tried to remove <Slot />
from HomeLayout and ExerciseDetailsLayout and got an empty screen (Header and Bottom TabBar preserved)
Tried declaring ExerciseDetails Stack directly in (tabs)/_layout.tsx like this but also did not work:
<Tabs
initialRouteName="(home)"
screenOptions={{
tabBarStyle: {
height: 75,
backgroundColor: THEME.colors.gray[600],
borderColor: THEME.colors.gray[600],
},
tabBarActiveTintColor: THEME.colors.green[500],
tabBarInactiveTintColor: THEME.colors.gray[300],
}}
>
<Tabs.Screen
name="(home)"
options={{
title: "",
headerShown: false,
tabBarIcon: ({ size, color }) => (
<House
size={size}
color={color}
weight={color === THEME.colors.green[500] ? "bold" : "regular"}
/>
),
}}
/>
<Stack.Screen
name="(exercise_details)"
options={{ headerShown: false }}
/>
<Tabs.Screen
name="(history)"
options={{
title: "",
headerShown: false,
tabBarIcon: ({ size, color }) => (
<ClockCounterClockwise
size={size}
color={color}
weight={color === THEME.colors.green[500] ? "bold" : "regular"}
/>
),
}}
/>
<Tabs.Screen
name="(profile)"
options={{
title: "",
headerShown: false,
tabBarIcon: ({ size, color }) => (
<UserCircle
size={size}
color={color}
weight={color === THEME.colors.green[500] ? "bold" : "regular"}
/>
),
}}
/>
</Tabs>
Upvotes: 1
Views: 1416
Reputation: 26
I recommend to have the <tabs></tabs>
labels in (home)/_layout.tsx,
in order to avoid confusing the router.
Upvotes: 0