skip to Main Content

I am trying to set an initial route in my react native app. When I created the app with "npx create-expo-app@latest", the app got built with some template pages.
I have created an onboarding page and i want the app to open on that screen.

This is onboarding.tsx

import React from "react";
import { View, Text, Button } from "react-native";
import { useRouter } from "expo-router";

export default function Onboarding() {
    const router = useRouter();

    const finishOnboarding = () => {
        router.replace("/");
    };

    return (
        <View
            style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
            <Text>Welcome to the app!</Text>
            <Button title="Get Started" onPress={finishOnboarding} />
        </View>
    );
}

This is the app/_layout.tsx:

import {
    DarkTheme,
    DefaultTheme,
    ThemeProvider,
} from "@react-navigation/native";
import { useFonts } from "expo-font";
import { Stack } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { useEffect } from "react";
import "react-native-reanimated";

import Onboarding from "./onboarding";

import { useColorScheme } from "@/hooks/useColorScheme";

SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
    const colorScheme = useColorScheme();
    const [loaded] = useFonts({
        SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
    });

    useEffect(() => {
        if (loaded) {
            SplashScreen.hideAsync();
        }
    }, [loaded]);

    if (!loaded) {
        return null;
    }

    return (
        <ThemeProvider
            value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
            <Stack initialRouteName="/onboarding">
                <Stack.Screen
                    name="onboarding"
                    options={{ headerShown: false }}
                />
                <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
                <Stack.Screen name="+not-found" />
            </Stack>
        </ThemeProvider>
    );
}

The app is still opening on the tabs page. Why is this? And how can the app open on onboarding.tsx?

The file router structure is like this:

app
/(tabs)
       /_layout.tsx
       /explore.tsx
       /index.tsx
/_layout.tsx
/onboarding.tsx
/+html.tsx
/+not-found.tsx

2

Answers


  1. I’m also facing with this problem. I guess, it’s an expo-router bug. You can simply use app/index.tsx page for redirecting.

    // app/index.tsx
    import { Redirect } from "expo-router";
    
    export default function IndexPage () {
        return <Redirect href="/onboarding" />;
    };
    
    Login or Signup to reply.
  2. It is not a bug.

    Expo router, by default, will search out the first index.tsx file it can find.

    In your layout that would be /(tabs)/index.tsx. This is because the (tabs) is a group because it is enclosed in parens. In effect this is your root "/" route.

    I prefer to either redirect or use "useRouter()" to navigate to my initial route.

    I would rewrite to something like this:

    import {
        DarkTheme,
        DefaultTheme,
        ThemeProvider } from "@react-navigation/native";
    import { useFonts } from "expo-font";
    import { Stack } from "expo-router";
    import * as SplashScreen from "expo-splash-screen";
    import { useEffect } from "react";
    import "react-native-reanimated";
    
    import Onboarding from "./onboarding";
    
    import { useColorScheme } from "@/hooks/useColorScheme";
    import { useRootNavigationState, useRouter } from "expo-router";
    
    SplashScreen.preventAutoHideAsync();
    
    export default function RootLayout() {
        //-- new
        const rootNavigationState = useRootNavigationState();
        const navigatorReady = rootNavigationState?.key != null;
        const router = useRouter();
        //-- 
        const colorScheme = useColorScheme();
        const [loaded] = useFonts({
            SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
        });
        //--updated
        useEffect(() => {
            if (loaded && navigatorReady) {
                SplashScreen.hideAsync();
                router.push('/onboarding.tsx')
            }
        }, [loaded, navigatorReady]);
    
        if (!loaded) {
            return null;
        }
    
        return (
            <ThemeProvider
                value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
                <Stack initialRouteName="/onboarding">
                    <Stack.Screen
                        name="onboarding"
                        options={{ headerShown: false }}
                    />
                    <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
                    <Stack.Screen name="+not-found" />
                </Stack>
            </ThemeProvider>
        );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search