Repository: expo/router

Issue #675: Screen flicker
Created: 2023-06-21T04:04:39Z
Which package manager are you using? (Yarn is recommended)
npm
Summary
I used the authentication/redirect flow proposed in the documentation (https://expo.github.io/router/docs/guides/auth), but it uses a useEffect to make the redirection. All children of the Auth Provider can still be rendered before the redirection is done. That cause page flicker.
Some examples:

Go to Login Page -> Click on Login -> Redirect To Home Page -> (Login Page Flicker) -> Home Page
Trying to access the Login page while already logged in -> Redirect to Home Page -> (Login Page Flicker) -> Home Page

Is there a clean way to prevent page flicker when making these kind of redirection?
Thanks
Minimal reproducible example
Auth Provider
import { useRouter, useSegments } from "expo-router";
import React from "react";

const AuthContext = React.createContext(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) {
  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 sign-in page.
      router.replace("/sign-in");
    } else if (user && inAuthGroup) {
      // Redirect away from the sign-in page.
      router.replace("/");
    }
  }, [user, segments]);
}

export function Provider(props) {
  const [user, setAuth] = React.useState(null);

  useProtectedRoute(user);

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

Root Layout
import { Slot } from "expo-router";
import { Provider } from "../context/auth";

export default function Root() {
  return (
    // Setup the auth context and render our layout inside of it.
    <Provider>
      <Slot />
    </Provider>
  );
}

Duplicate issue #774: iOS Only - Flicker when i use Stack layout
Created: 2023-07-13T09:44:07Z
Which package manager are you using? (Yarn is recommended)
yarn
Summary
I use expo router v2 after upgrading from expo 48 to expo 49
When I want to use multiple stack layouts, I get a flicker when I change layout.
If I don't use layouts, I don't have any problems, but then I don't have a transition.
(You can see the 2 cases in videos)
Minimal reproducible example
Here is my structure :

my main layout :

import { AuthProvider } from "@/src/context/auth";
import { ThemeProvider } from "@/src/context/theme";
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
import { FontSource, useFonts } from "expo-font";
import { Slot, SplashScreen } from "expo-router";
import { useEffect } from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { QueryClient, QueryClientProvider } from "react-query";

type Font = {
  [key: string]: FontSource;
};

const queryClient = new QueryClient();

SplashScreen.preventAutoHideAsync();

export default function Root() {
  const [fontsLoaded] = useFonts({
    "Inter-Black": require("../assets/fonts/Inter-Black.ttf") as Font,
    "Inter-Bold": require("../assets/fonts/Inter-Bold.ttf") as Font,
    "Inter-ExtraBold": require("../assets/fonts/Inter-ExtraBold.ttf") as Font,
    "Inter-ExtraLight": require("../assets/fonts/Inter-ExtraLight.ttf") as Font,
    "Inter-Light": require("../assets/fonts/Inter-Light.ttf") as Font,
    "Inter-Medium": require("../assets/fonts/Inter-Medium.ttf") as Font,
    "Inter-Regular": require("../assets/fonts/Inter-Regular.ttf") as Font,
    "Inter-SemiBold": require("../assets/fonts/Inter-SemiBold.ttf") as Font,
    "Inter-Thin": require("../assets/fonts/Inter-Thin.ttf") as Font,
  });

  useEffect(() => {
    if (fontsLoaded) {
      //setTimeout to prevent to see the first screen
      setTimeout(() => {
        SplashScreen.hideAsync();
      }, 1);
    }
  }, [fontsLoaded]);

  if (!fontsLoaded) {
    return null;
  }

  return (
    <BottomSheetModalProvider>
      <SafeAreaProvider>
        <ThemeProvider>
          <AuthProvider>
            <QueryClientProvider client={queryClient}>
              <Slot />
            </QueryClientProvider>
          </AuthProvider>
        </ThemeProvider>
      </SafeAreaProvider>
    </BottomSheetModalProvider>
  );
}


my 2 others layouts :

import { Stack } from "expo-router";
import React from "react";

export default function Layout() {
  return <Stack screenOptions={{ headerShown: false }} />;
}


the videos :

  
    
    

    NoFlicker.mp4
    
  

  

  



  
    
    

    Flicker.mp4

Closing comment (2023-07-13T23:19:05Z): Duplicate #675