Thomas Domenig
Thomas Domenig

Reputation: 31

Expo splash screen not hiding because of react navigator

This is my first post on stackoverflow, so bare with me.

I posted a problem concerning expo splash screen not hiding in my android preview build when using a react navigation navigator, even in a minimal example. In the mean time I have solved it (see below) but I leave the post for anybody who runs into the same problem.

I have a standard setup showing the splash screen until fonts are loaded and the app is ready. At that moment, the splash screen should hide and the react navigator should be rendered. This works as expected in expo go, but in a preview build the splash screen just doesn't hide. This is specific to react navigator. If I replace the navigator by another component, everything is fine.

I tried to debug this as best as I could but it seems difficult because the problem only occurs in the android build. The code of my failing example is as follows (basically copy/pasted from expo homepage and react navigation homepage).

import React, { useCallback, useEffect, useState } from 'react';
import { Text, View } from 'react-native';
import Entypo from '@expo/vector-icons/Entypo';
import * as Font from 'expo-font';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

import * as SplashScreen from 'expo-splash-screen';

// Keep the splash screen visible while we fetch resources
SplashScreen.preventAutoHideAsync();

const Stack = createNativeStackNavigator();

export default function App() {
  const [appIsReady, setAppIsReady] = useState(false);

  useEffect(() => {
    async function prepare() {
      try {
        await Font.loadAsync(Entypo.font);
      } catch (e) {
        console.warn(e);
      } finally {
        // Tell the application to render
        setAppIsReady(true);
      }
    }
    prepare();
  }, []);

  const onLayoutRootView = useCallback(async () => {
    if (appIsReady) {
      await SplashScreen.hideAsync();
    }
  }, [appIsReady]);

  if (!appIsReady) {
    return null;
  }

  return (
    <View onLayout={onLayoutRootView} style={{flex: 1}} >
      <NavigationContainer >
        <Stack.Navigator>
        <Stack.Screen name="Home Screen" component={HomeScreen} options={{ title: 'Oops!' }} />
        </Stack.Navigator>
      </NavigationContainer>
    </View>
  );
}

function HomeScreen() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>This is the Home Screen</Text>
    </View>
  );
}

I'm using expo ^50.0.17, react-navigation/native-stack ^6.9.26.

In the mean time I have made a fresh minimal project but with same result, i.e the splash screen hides in expo go as expected but not in android build.

Here is my package.json

{
  "name": "gafapp4",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@react-navigation/native": "^6.1.17",
    "@react-navigation/native-stack": "^6.9.26",
    "expo": "~50.0.14",
    "expo-status-bar": "~1.11.1",
    "react": "18.2.0",
    "react-native": "0.73.6",
    "expo-splash-screen": "~0.26.4"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

As stated above, I have meanwhile identified and solved the problem. All I had to do is install the following packages:

Actually this is described in the instructions on upgrading from react navigation 5 to react navigation 6 (see https://reactnavigation.org/docs/upgrading-from-5.x/) so I am to blame for not reading those properly.

Upvotes: 3

Views: 791

Answers (1)

Florian Erwerth
Florian Erwerth

Reputation: 94

You can use useFonts from expo which gives you back an array with a isReady property.

const [interLoaded] = useFonts({
    Inter: require('@tamagui/font-inter/otf/Inter-Medium.otf'),
    InterBold: require('@tamagui/font-inter/otf/Inter-Bold.otf'),
});

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

Upvotes: 0

Related Questions