Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initialRouteName has no effect #723

Open
ep1kt3t0s opened this issue Jul 3, 2023 · 32 comments
Open

initialRouteName has no effect #723

ep1kt3t0s opened this issue Jul 3, 2023 · 32 comments

Comments

@ep1kt3t0s
Copy link

Which package manager are you using? (Yarn is recommended)

npm

Summary

On a fresh Expo project with tabs and Typescript, the unstable_settings.initialRouteName has no effect.

I also tested <Stack initialRouteName=...> and it also has no effect.

Basically, any directory with parenthesis (something) alphabetically at the top becomes the default route, unless there is an index directory.

This doesn't correlate with what's described in the documentation: https://expo.github.io/router/docs/features/routing/#layout-settings

Minimal reproducible example

Steps to reproduce:

Step 1, Environment

$ npx expo --version
0.7.3

$ npx expo init --npm
Select: tabs (TypeScript)

Step 2, Testing the effect

Duplicate (tabs) directory and rename the duplicate to (a)
Update some text in (a)/index.ts
Add <Stack.Screen name="(a)" options={{ headerShown: false }} /> into the <Stack>

Result: (a) will be the default route without unstable_settings.initialRouteName is updated. You can set anything to unstable_settings.initialRouteName, there is no effect.

@eridr
Copy link

eridr commented Sep 11, 2023

Only when both unstable_settings and initialRouteName in the Stack is used then it works. 🤷‍♂️

@NiklasEi
Copy link

I am running into this when deep linking from one tab with its own stack to another tab with its own stack. There is no back button for the deep linked page although, unstable_settings.initialRouteName and initialRouteName on the deep linked Stack are configured.

@suhail135
Copy link

import { Redirect } from "expo-router";

const Index = () => {
	return <Redirect href="/onboarding" />;
};
export default Index;

i know it's not a proper solution. for now am going with this.

check out : #428

@matthewhausman
Copy link

matthewhausman commented Jan 2, 2024

I'm able to use this to impact the router history with groups. My initial problem was I couldn't figure out how to have proper pop/push animations. I always wanted anything in (auth) group to pop and anything in (tabs) to push. Turned out I just had to export this in the root layout:

export const unstable_settings = {
  initialRouteName: '(auth)',
}

@Zenb0t
Copy link

Zenb0t commented Jan 30, 2024

Well, I'm running into the same issue. After running a few investigations, if you console.log each route component, you see that the components are really mounting, but the redirect is being redirected again to the index of (tabs), for some unknown reason.

The render order is "initial route" > "login" > "(tabs)/index". I tested both reloading and from a fresh start. Clearing the cache with -c had no effect. However, if you don't navigate when the app loads, and you do a fast refresh from a change in the code, the route properly initiates in the correct route. However, any attempt to open the app defaults to tabOne in the template.

Navigating from the Expo Go app, you go straight to "(tabs)/index".

package.json

   "expo": "~50.0.4",
   "expo-router": "~3.4.6",
    

@dominictobias
Copy link

Same issue, I set initialRouteName and in unstable_settings on every _layout (unclear which to use) and none have any effect, the initial route is always "/"

@jimpala
Copy link

jimpala commented Apr 16, 2024

The React Navigation -> Expo Router migration guide seems to imply that the initialRouteName on navigators like <Stack> is a no-op - it's whatever index is for a navigator that determines the initial route.
And it seems that the same property in unstable_settings is purely there to determine where the back button goes to on an initial render in the case of something like deep linking - it doesn't seem to dictate anything to do with what renders first on an ordinary boot of the app.

With this in mind I think (tabs)/index as the initial route would be the expected behaviour because (tabs) is a group and hence doesn't contribute to a routing URL segment, therefore (tabs/index) is effectively index? And if there is no index it just looks for the first screen at the top level alphabetically?

The docs could probably be a bit clearer that initialRouteName on the navigators don't have any effect? And unstable_settings.initialRouteName seems a bit of a misleading name. Idk

@eybel
Copy link

eybel commented Jun 6, 2024

I have a case where my new app goes to (auth) >. index.tsx instead of (tabs) > index.tsx. initialRouteName doesnt work

@curiosbasant
Copy link

I have a case where my new app goes to (auth) >. index.tsx instead of (tabs) > index.tsx. initialRouteName doesnt work

In that case, specify the initial route like this, (auth)/index.

@eybel
Copy link

eybel commented Jun 16, 2024

I have a case where my new app goes to (auth) >. index.tsx instead of (tabs) > index.tsx. initialRouteName doesnt work

In that case, specify the initial route like this, (auth)/index.

But I wanted to go to (tabs)/index.tsx. I set the initialRouteName up to "(tabs)". I have up and used redirections

@kyranjamie
Copy link

Very confusing.

Not only it doesn't work, but initialRouteName is accepted on <Stack />, <Slot />, and unstable_settings yet does nothing.

@Fusinix
Copy link

Fusinix commented Jul 8, 2024

I encountered the same issue with initialRouteName not working properly in my Expo Router setup. Here is how I solved it:

1. Loading Fonts and Authentication State in app/_layout.tsx

  • In the _layout.tsx file of the app directory, I kept the splash screen on while loading fonts via expo-font.
  • Additionally, I checked the authenticated state of the user (optional).
  • All this is happens while the splash screen is still visible tho.
import { useEffect, useState } from "react";
import { SplashScreen } from "expo";
import * as Font from "expo-font";
import { Stack } from "expo-router";

//keep the splash screen on
SplashScreen.preventAutoHide();

export default function RootLayout() {
  const [fontsLoaded, setFontsLoaded] = useState(false);
  const [isAuthenticated, setIsAuthenticated] = useState(null);
  const router = useRouter();

  useEffect(() => {
    const loadFonts = async () => {
      await Font.loadAsync({
        // Add your custom fonts here
        "Roboto-Regular": require("./assets/fonts/Roboto-Regular.ttf"),
      });
      setFontsLoaded(true);
    };

    const checkAuthStatus = async () => {
      // Your logic to check if the user is authenticated
      const status = await getAuthStatusFromYourService();
      setIsAuthenticated(status);
    };

    loadFonts();
    checkAuthStatus();
  }, []);

  if (!fontsLoaded) {
  
    return null;
  }

  return <Stack screenOptions={{ your-prefered-config }} />;
}

Using in app/index.tsx:

  • I created an index.tsx file where I used the <Redirect> component from expo-router to navigate to the desired route or route group (tabs) or (main) or (auth) or (whatever-route).
  • A loading animation is displayed while checking if useRootNavigationState()?.key hook from Expo Router is not undefined my way of checking is the root navigation is ready.
  • If no key is found, the loading animation continues until useRootNavigationState()?.key is not undefined, then it returns the <Redirect> component.
import { Redirect, Slot, Stack, useRootNavigationState } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { useEffect, useState } from "react";

import { ActivityIndicator, Platform, StatusBar } from "react-native";
import colors from "@/constants/colors/index";
import { Provider } from "react-redux";
import { store } from "@/redux/store";
import useCustomFonts from "@/hooks/useCustomFonts";
import useAuthStatus from "@/hooks/useAuthStatus";
import ScreenLayout from "@/components/styles/layout/screen-layout";
import CView from "@/components/custom/CView";
import useTheme from "@/utils/hooks/theme/useTheme";

export const unstable_settings = {
  initialRouteName: "(test)",
};

export const platform = Platform.OS;

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
  const isAuthenticated = useAuthStatus();
  const theme = useTheme();
  const navigation = useRootNavigationState();
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    // check if navigation state is ready to prevent flickering when redirecting
    if (!navigation?.key) return;
    // if navigation state is ready, hide splash screen
    SplashScreen.hideAsync();
    setIsReady(true);
  }, [navigation?.key]);

  if (!isReady || isAuthenticated === "loading") {
    return (
      <ScreenLayout>
        <CView _className="flex-1 items-center justify-center">
          <ActivityIndicator size="large" color={colors.accent[theme]} />
        </CView>
      </ScreenLayout>
    );
  }

  return <Redirect href={"/(test)"} />;
}

Fix for Flickering issue during redirects immediately after app launch

Notice I'm rather hiding the splash screen in this file, this is to solve the flickering issue caused by the redirect.
You just have to wait for navigation state to be ready (thus useRootNavigationState()?.key must not be undefined)

The trick here is to include an index.tsx file in the route of your group directory to handle redirects.

@carlosriveroib
Copy link

Same here

@osmanemin
Copy link

I think all solutions are confused. My solutions:

Set the redirect prop of Stack.Screen to true for the index page.

app/_layout.tsx

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

SplashScreen.preventAutoHideAsync();

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

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

  if (!loaded) {
    return null;
  }

  return (
    <Stack >
      <Stack.Screen name="index" options={{ headerShown: false }} redirect />
      <Stack.Screen name="login" options={{ headerShown: false }} />
      <Stack.Screen name="about" options={{ headerShown: false }} />
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen name="+not-found" />
    </Stack>
  );
}

Index page will redirects to first sibling page

@Osama92
Copy link

Osama92 commented Aug 19, 2024

@osmanemin adding redirect did the trick 🎉🎉

@andres-dos-santos
Copy link

I just created an index folder at the same level as _layout and added a redirect inside it.

import { type Href, Redirect } from 'expo-router'

import { useUser } from '@/hooks/use-user'

export default function RedirectPage() {
  const { user } = useUser()

  const href = (user ? '(tabs)' : '(auth)') as Href

  return <Redirect href={href} />
}

If initialRouteName worked you wouldn't need this, but it's also a solution.

@ragnarok22
Copy link

@andres-dos-santos you are a true hero. It works perfectly. Thank you!

@Mako-L
Copy link

Mako-L commented Oct 1, 2024

What is the status of this will you guys make the initialRouteName or we will keep flash screening people :D.

@aike19115
Copy link

Ran into the same issue, it would be good if the prop initialRouteName is removed while it is not functioning as expected

@sekoyo
Copy link

sekoyo commented Oct 16, 2024

We ended up using react navigation directly which after a small amount of setup was much easier than trying to solve these issues and more intuitive regarding nested navigators

@rizbud
Copy link

rizbud commented Oct 26, 2024

I don't think expo-router is stable and production ready unless this issue is resolved

@JoaoVitorJJV
Copy link

JoaoVitorJJV commented Nov 3, 2024

I don't think expo-router is stable and production ready unless this issue is resolved

Same here. I got two errors, the "Unmatched Route", which is resolved by changing the name of the _layout.tsx file to index. However, when doing this, the screen turns white as there are no redirects.

How can you develop if you can't at least see what you're developing?

Using react-navigation seems to be the best choice

@suhail135
Copy link

I don't think expo-router is stable and production ready unless this issue is resolved

Flet the same 🥲

@DanielAdari
Copy link

@osmanemin 's solution worked for me!
Thanks :)

@svenngronbeck
Copy link

svenngronbeck commented Nov 9, 2024

Probably not the case for everyone here, but if you use shared routes or groups, remember that

when reloading the page, the first alphabetical match is rendered.

Given a BottomTabs layout with groups within each tab, structured like this:

-(tabs)
---(index)
-----_layout.tsx
-----index.tsx
---(someRandomName)
-----_layout.tsx
-----index.tsx
---(anotherRandomName)
-----_layout.tsx
-----index.tsx
-_layout.tsx

This would alphabetically match with (anotherRandomName) first and therefore render that initially.

Notice there's no index file within (tabs), as that would create an additional item in the BottomTab navbar. In this case, I only want the three specific items in my navbar: (index), (someRandomName) and (anotherRandomName).

I tried added a (tabs)/index file, with <Redirect href='(index)' /> as suggested @andres-dos-santos. This worked, but added an unwanted item into my BottomTab navbar.

What finally worked was renaming the groups:

-(tabs)
---(Aindex)
-----_layout.tsx
-----index.tsx
---(BsomeRandomName)
-----_layout.tsx
-----index.tsx
---(CanotherRandomName)
-----_layout.tsx
-----index.tsx
-_layout.tsx

I just added letters to the start of each group name so that it aplhabetically matches on my first group.

I find it strange, but at least it works.

@buildnewapp
Copy link

I used to operate like this before.:

app/(tabs)/index.js:

    useEffect(()=>{
        setTimeout(()=>{
            routerTo('/card')
        },300)
    }, [])

Operating like this now will be more elegant.:
app/index.js

import { Redirect } from 'expo-router'

export default function RedirectPage() {
    const firstStart  = false
    const href = (firstStart ? '(common)/guide' : '(tabs)/card')
    return <Redirect href={href} />
}

@jeffreymonjacastro
Copy link

@andres-dos-santos thank you! It did work

@csulit
Copy link

csulit commented Nov 11, 2024

Well, I'm running into the same issue. After running a few investigations, if you console.log each route component, you see that the components are really mounting, but the redirect is being redirected again to the index of (tabs), for some unknown reason.

The render order is "initial route" > "login" > "(tabs)/index". I tested both reloading and from a fresh start. Clearing the cache with -c had no effect. However, if you don't navigate when the app loads, and you do a fast refresh from a change in the code, the route properly initiates in the correct route. However, any attempt to open the app defaults to tabOne in the template.

Navigating from the Expo Go app, you go straight to "(tabs)/index".

package.json

   "expo": "~50.0.4",
   "expo-router": "~3.4.6",
    

This one works.

// eslint-disable-next-line camelcase
export const unstable_settings = {
  // Ensure that reloading on `/modal` keeps a back button present.
  initialRouteName: "(tabs)/index",
}

@masarbazi
Copy link

same issue, so annoying 😑

@MehediH
Copy link

MehediH commented Nov 23, 2024

hi folks, i am having the same issue with the initial route name, but I also couldn't get unstable_settings to work, this is a part of my sitemap:

image

Essentially I have:

_layout.tsx (root layout)
--> onboarding (Stack) // not relevant
--> loggedIn (Stack) // main stack
        _layout.tsx (for loggedIn)
----->  tabs (Tabs)
        _layout.tsx (for tabs)
----->  chat (Stack)
         _layout.tsx (for chat)
         chatList
         chatScreen

I am trying to set up deep linking into the chatScreen, and that works, but the users aren't able to go back to the previous screen (chatList) because of the issue w/ initialRouteName.

I have tried multiple variations of unstable_settings without any luck. Can someone help me figure out what the correct settings should be, and which _layout.tsx file it should go in? Thanks!

@skyllex94
Copy link

This was my approach and it works well for me, so I simply guide it to an index screen which holds the logic inside

              <Stack.Screen
                  name="index"
                  initialParams={{ appFirstOpened }}
                />

and inside index use the passed initial param to guide it to the right screen to be displayed

import {  useLocalSearchParams } from "expo-router";
import OnBoarding from "./onboarding";
import MainScreen from "./main";

// Dividing the screens to go to Main or OnBoarding
export default function Index() {
  let isFirstOpen = null;

  const params = useLocalSearchParams();
  const { appFirstOpened } = params;

  // Read the param and translate it to Boolean
  if (appFirstOpened === "true") isFirstOpen = true;
  else isFirstOpen = false;

  return isFirstOpen ? <OnBoarding /> : <MainScreen />;
}

Make sure every step of the way you parse the param into a boolean since it always stringifies it.

@ragnarok22
Copy link

I did something similar. In your case I would replace that if for

isFirstOpen = appFirstOpened === "true"

This was my approach and it works well for me, so I simply guide it to an index screen which holds the logic inside

              <Stack.Screen
                  name="index"
                  initialParams={{ appFirstOpened }}
                />

and inside index use the passed initial param to guide it to the right screen to be displayed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests