Repository: expo/router

Issue #349: Cannot read property 'type' of undefined.
Created: 2023-03-06T10:59:22Z
Summary
Hi!,
In app, we used 3 layouts - RootLayout, TabLayout, HomeLayout
and we used the useLocation Hook on the home screen and got this error and getRootState is undefined.

Minimal reproducible example
for minimal reproducible example i created a repo.
https://github.com/ak151997galaxy/expo-router-tabs

Duplicate issue #370:  ERROR  TypeError: Cannot read property 'type' of undefined  
Created: 2023-03-12T02:29:24Z
Summary
The error happens on Android and seems to be related to the fact that my AuthProvider is using router.replace() too quickly somehow?
 ERROR  TypeError: Cannot read property 'type' of undefined

This error is located at:
    in AuthProvider (created by RootLayout)
    in ApolloProvider (created by ApolloProvider)
    in ApolloProvider (created by RootLayout)
    in $29383e587d62412a$export$9f8ac96af4b1b2ae (created by NativeBaseProvider)
    in ToastProvider (created by NativeBaseProvider)
    in PortalProvider (created by NativeBaseProvider)
    in HybridProvider (created by NativeBaseProvider)
    in ResponsiveQueryProvider (created by NativeBaseProvider)
    in RNCSafeAreaProvider (created by SafeAreaProvider)
    in SafeAreaProvider (created by NativeBaseProvider)
    in NativeBaseConfigProviderProvider (created by NativeBaseProvider)
    in NativeBaseProvider (created by RootLayout)
    in RootLayout (created by Route(RootLayout))
    in Try (created by Route(RootLayout))
    in Route (created by Route(RootLayout))
    in LocationProvider (created by Route(RootLayout))
    in Route(RootLayout) (created by RootRoute)
    in RootRoute (created by ContextNavigator)
    in InitialRootStateProvider (created by ContextNavigator)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by NavigationContainer)
    in NavigationContainer (created by ContextNavigator)
    in RootRouteNodeProvider (created by ContextNavigator)
    in ContextNavigator (created by ExpoRoot)
    in RNCSafeAreaProvider (created by SafeAreaProvider)
    in SafeAreaProvider (created by ExpoRoot)
    in RNGestureHandlerRootView (created by GestureHandlerRootView)
    in GestureHandlerRootView (created by GestureHandler)
    in GestureHandler (created by ExpoRoot)
    in ExpoRoot (created by App)
    in App (created by withDevTools(App))
    in withDevTools(App) (created by ErrorOverlay)
    in ErrorToastContainer (created by ErrorOverlay)
    in ErrorOverlay
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in main(RootComponent), js engine: hermes


Minimal reproducible example
import FontAwesome from "@expo/vector-icons/FontAwesome";
import { useFonts } from "expo-font";
import { SplashScreen, Stack } from "expo-router";
import { Text, NativeBaseProvider } from "native-base";
import { useEffect } from "react";
import theme from "~/components/theme";
import { AuthProvider } from "~/providers/AuthProvider";

export {
  // Catch any errors thrown by the Layout component.
  ErrorBoundary,
} from "expo-router";

export const unstable_settings = {
  // Ensure that reloading on `/modal` keeps a back button present.
  initialRouteName: "(tabs)",
};

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

  // Expo Router uses Error Boundaries to catch errors in the navigation tree.
  useEffect(() => {
    if (error) throw error;
  }, [error]);

  return (
    <NativeBaseProvider theme={theme}>
        <AuthProvider>
          {!loaded && (
            <>
              <Text>splash</Text>
              <SplashScreen />
            </>
          )}
          {loaded && <RootLayoutNav />}
        </AuthProvider>
    </NativeBaseProvider>
  );
}

function RootLayoutNav() {
  // TODO: show splash screen while making sure auth token is valid and loading user info
  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen
        name="(auth)/signin"
        options={{
          headerTitle: "Sign In",
          headerShown: true,
        }}
      />
      <Stack.Screen
        name="(auth)/signup"
        options={{
          headerTitle: "Sign Up",
          headerShown: true,
        }}
      />
      <Stack.Screen name="modal" options={{ presentation: "modal" }} />
    </Stack>
  );
}
// import { useQuery, gql } from "@apollo/client";
// import * as SecureStore from "expo-secure-store";
import { useRouter, useSegments } from "expo-router";
import React from "react";

interface AuthContextType {
  signIn: (id: number) => void;
  signOut: () => void;
  user: User | null;
}

interface User {
  id: number;
}

const AuthContext = React.createContext<AuthContextType | null>(null);

// This hook can be used to access the user info.
export function useAuth() {
  return React.useContext(AuthContext);
}

// This hook will protect the route access based on user authentication.
function useProtectedRoute(user: User | null) {
  const segments = useSegments();
  const router = useRouter();

  React.useEffect(() => {
    const inAuthGroup = segments[0] === "(auth)";

    if (
      // If the user is not signed in and the initial segment is not anything in the auth group.
      !user &&
      !inAuthGroup
    ) {
      // Redirect to the login page.
      router.replace("/(auth)/signup");
    } else if (user && inAuthGroup) {
      // Redirect away from the sign-in page.
      router.replace("/");
    }
  }, [user, segments]);
}

export function AuthProvider(props: React.PropsWithChildren) {
  const [user, setUser] = React.useState<User | null>(null);

  useProtectedRoute(user);

  return (
    <AuthContext.Provider
      value={{
        signIn: (id: number) => setUser({ id }),
        signOut: () => setUser(null),
        user,
      }}
    >
      {props.children}
    </AuthContext.Provider>
  );
}

export default AuthProvider;

Closing comment (2023-03-13T16:24:33Z): Duplicate of #349