11

I made Expo app with react native navigation 5.

please refer my solved question(same install situation).

but After splash on FIRST launching, White screen is blink(Flashed : about 0.5 sec). Especially, At Dark theme, I can find this bug easily.

This is App.tsx

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';

import useCachedResources from './hooks/useCachedResources';
import useColorScheme from './hooks/useColorScheme';
import Navigation from './navigation';

export default function App() {
  const isLoadingComplete = useCachedResources();
  const colorScheme = useColorScheme();

 if (!isLoadingComplete) {
    return null;
  } else {
    return (
      <SafeAreaProvider>
        <Navigation colorScheme={colorScheme} />
        <StatusBar style='light'/>
      </SafeAreaProvider>
    );
  }
}

and this is index.tsx at nvigation

import { RootStackParamList } from '../types';
import BottomTabNavigator from './BottomTabNavigator';
import LinkingConfiguration from './LinkingConfiguration';

export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
  return (
    <NavigationContainer
      linking={LinkingConfiguration}
      theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
      <RootNavigator />
    </NavigationContainer>
  );
}

const Stack = createStackNavigator<RootStackParamList>();

function RootNavigator() {
  return (
    <Stack.Navigator screenOptions={{ headerShown: false }}>
      <Stack.Screen name="Root" component={BottomTabNavigator} />
      <Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
    </Stack.Navigator>
  );
}

At Hook, useCachedResources.ts

import { MaterialIcons } from '@expo/vector-icons';
import * as Font from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import * as React from 'react';

export default function useCachedResources() {
  const [isLoadingComplete, setLoadingComplete] = React.useState(false);
  React.useEffect(() => {
    async function loadResourcesAndDataAsync() {
      try {
        SplashScreen.preventAutoHideAsync();

        await Font.loadAsync({
          ...MaterialIcons.font,
          'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf'),
        });
      } catch (e) {
        console.warn(e);
      } finally {
        setLoadingComplete(true);
        SplashScreen.hideAsync();
      }
    }
    loadResourcesAndDataAsync();
  }, []);

  return isLoadingComplete;
}

and useColorScheme.ts

import { Appearance, ColorSchemeName } from 'react-native';
import { useEffect, useRef, useState } from 'react';

export default function useColorScheme(delay = 500): NonNullable<ColorSchemeName> {
  const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());

  let timeout = useRef<NodeJS.Timeout | null>(null).current;

  useEffect(() => {
    Appearance.addChangeListener(onColorSchemeChange);

    return () => {
      resetCurrentTimeout();
      Appearance.removeChangeListener(onColorSchemeChange);
    };
  }, []);

  function onColorSchemeChange(preferences: Appearance.AppearancePreferences) {
    resetCurrentTimeout();

    timeout = setTimeout(() => {
      setColorScheme(preferences.colorScheme);
    }, delay);
  }

  function resetCurrentTimeout() {
    if (timeout) {
      clearTimeout(timeout);
    }
  }

  return colorScheme as NonNullable<ColorSchemeName>;
}

How to solve this bug? Please give me your hand.

Bennie Kim
  • 143
  • 1
  • 5
  • 2
    Adding, If I insert code(setTimeout(() => {SplashScreen.hideAsync();}, 300) at useCachedResources.ts, this bug was hidden. But I think that it is not a solution basically – Bennie Kim Nov 11 '20 at 04:27
  • 2
    I've got the same issue, the timeout is the only solution I have found... – Tomas Gonzalez Dec 22 '20 at 02:44
  • 1
    The timout worked for me too, but it would be great if there is a more reliable solution. – Obay Abd-Algader Feb 13 '23 at 06:45
  • 1
    as of 2023, expo splash screen updated their docs to place hideAsync inside of an onLayoutRootView with useCallback. Still had to resort to @BennieKim's solution of using timeout. placed `await new Promise((resolve) => setTimeout(resolve, 300)); await SplashScreen.hideAsync();` inside of the useCallback in order to get ride of the white screen blink. Couldn't find any other solution – PhilVarg Apr 27 '23 at 18:19

5 Answers5

7

I just solved this issue by specifying backgroundColor in my app.json to match the background color of the splash screen.

Expo Docs for backgroundColor

(string) - The background color for your app, behind any of your React views. This is also known as the root view background color. 6 character long hex color string, for example, '#000000'. Default is white: '#ffffff'.

Alex
  • 676
  • 9
  • 20
2

Try to use SplashScreen.preventAutoHideAsync() in your App.js before its declaration.

For example:

SplashScreen.preventAutoHideAsync();

export default function App() {
...

Don't forget to delete the SplashScreen.preventAutoHideAsync() call in your loadResourcesAndDataAsync() function. Keep it only in the App.js file.

I hope this help you. Worked for me.

zyc
  • 344
  • 3
  • 7
0

This can be done in two ways.

  1. Install the package with npx expo install expo-system-ui and add the following lines to the root file (outside of the component):

    import * as SystemUI from "expo-system-ui";
    
    SystemUI.setBackgroundColorAsync("transparent");
    
    // Note: you will put the lines (above) outside the component
    export default function App() {
        return <></>;
    }
    
  2. Alternatively, add the backgroundColor to the app.json:

    {
       "expo": {
          name: "MyAwesomeApp",
          backgroundColor: "#00000000"
       }
    }
    
    

I prefer the first way because the "backgroundColor" in the app.json is expected to be an RRGGBB and we are providing an AARRGGBB.

Sufian
  • 6,405
  • 16
  • 66
  • 120
-1

Just got a breakthrough on this after few days so what you will modify in your index.ts file Note: this is only for expo react native

your code

function RootNavigator() {
 return (
   <Stack.Navigator screenOptions={{ headerShown: false }}>
      <Stack.Screen name="Root" component={BottomTabNavigator} />
      <Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 
      'Oops!' }} />
   </Stack.Navigator>
 );
}

what it should be :

function RootNavigator() {
  return (
   <Stack.Navigator initialRouteName="Root" screenOptions={{ headerShown: false 
   }}>
    <Stack.Screen name="Root" component={BottomTabNavigator} />
    <Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 
     'Oops!' }} />
   </Stack.Navigator>
 );
}

by adding initialRouteName your problem should get solved

Anthony phillips
  • 152
  • 3
  • 13
  • `initialRouteName` is by default the first screen available. Adding `initialRouteName="Root"` in this case does not change anything. – Pierre Jun 01 '23 at 18:14
-2

their other reason also makes sure that your import {useState,useEffect } or other hooks from react not react.development, you will face that if you published your app on the expo or generated API or apk

ahmed mersal
  • 167
  • 2
  • 3