Apploading threw an error

hello guy my app trow this error
AppLoading threw an unexpected error when loading:
Error: AppLoading onError prop is required if startAsync is provided

You can try to use a community AppLoading library; such as:

expo-app-loading

Also, you can reinstall the libraries.

In case, here’s my App.js:

import React, { useState } from 'react';
import AppLoading from 'expo-app-loading';
import { NavigationContainer } from '@react-navigation/native';
import AppNavigator from './app/navigation/AppNavigator';
import AuthContext from './app/auth/context';
import AuthNavigator from './app/navigation/AuthNavigator';
import NavigationTheme from './app/navigation/NavigationTheme';
import OfflineNotice from './app/components/OfflineNotice';
import authStorage from './app/auth/storage';

export default function App() {
  const [user, setUser] = useState();
  const [isReady, setIsReady] = useState(false);

  const restoreUser = async () => {
    const loginInfo = await authStorage.getUser();
    if (loginInfo) setUser(loginInfo);
  };

  if (!isReady) {
    return (
      <AppLoading
        startAsync={restoreUser}
        onFinish={() => setIsReady(true)}
        onError={console.warn}
      />
    );
  }

  return (
    <AuthContext.Provider value={{ user, setUser }}>
      <OfflineNotice />
      <NavigationContainer theme={NavigationTheme}>
        {user ? <AppNavigator /> : <AuthNavigator />}
      </NavigationContainer>
    </AuthContext.Provider>
  );
}

Since now AppLoading is deprecated I’ll post my solution using the SplashScreen module as suggested on the expo documentation.

First, install the SplashScreen module:

expo install expo-splash-screen

This is my App.js:

import React, { useCallback, useEffect, useState } from "react";
import { NavigationContainer } from "@react-navigation/native";
import jwtDecode from "jwt-decode";
import * as SplashScreen from "expo-splash-screen";

import AppNavigator from "./app/components/navigation/AppNavigator";
import AuthContext from "./app/auth/context";
import AuthNavigator from "./app/components/navigation/AuthNavigator";
import OfflineNotice from "./app/components/OfflineNotice";
import navigationTheme from "./app/components/navigation/navigationTheme";
import authStorage from "./app/auth/storage";

export default function App() {
    const [user, setUser] = useState();
    const [isReady, setIsReady] = useState(false);

    const restoreToken = async () => {
        const token = await authStorage.getToken();
        if (!token) return;
        setUser(jwtDecode(token));
    };

    useEffect(() => {
        async function prepare() {
            try {
                await SplashScreen.preventAutoHideAsync();
                await restoreToken();
            } catch (error) {
                console.log("Error loading app", error);
            } finally {
                setIsReady(true);
            }
        }

        prepare();
    }, []);

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

    if (!isReady) return null;

    return (
        <AuthContext.Provider value={{ user, setUser }}>
            <NavigationContainer theme={navigationTheme} onReady={onNavigationContainerReady}>
                {user ? <AppNavigator /> : <AuthNavigator />}
            </NavigationContainer>
            <OfflineNotice />
        </AuthContext.Provider>
    );
}
2 Likes

hello~ what is the link to your repository? i really want to see the solution

Sorry I don’t have a repository online but all the changes regarding the splash screen are on the App.js file i posted above. You just need to install the expo-splash-screen module and look at my App.js.

If you review SplashScreen Documentation the Usage section seems pretty clear cut (aka…I implemented it in about 3 minutes).

@deedeedev , I had the same problem, so I tried to use your code, but for some reason onNavigationContainerReady() was never fired.
Eventually, I made it by doing everything under useEffect:
(and then there is no need for onNavigationContainerReady() and the isReady hook)

  useEffect(() => {
    async function prepare() {
      try {
        await SplashScreen.preventAutoHideAsync();
        await restoreToken();
      } catch (error) {
        console.log("Error loading app", error);
      } finally {
        await SplashScreen.hideAsync();
      }
    }
    prepare();
  }, []);

What is actually the risk of doing that?

import { jwtDecode } from "jwt-decode";
import "core-js/stable/atob";
import * as SplashScreen from "expo-splash-screen";
// ... Other imports

SplashScreen.preventAutoHideAsync();

export default function App() {
  const [user, setUser] = useState();
  const [isReady, setIsReady] = useState(false);

  const restoreToken = async () => {
    const token = await authStorage.getToken();

    if (!token) return setIsReady(true);

    setUser(jwtDecode(token));
    setIsReady(true);
  };

  useEffect(() => {
    restoreToken();
  }, []);

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

  if (!isReady) {
    return null;
  }

  return (
    <View
      style={{ flex: 1 }}
      onLayout={onLayoutRootView}
    >
      <AuthContext.Provider value={{ user, setUser }} >
        <OfflineNotice />
        <NavigationContainer theme={navigationTheme}>
          {user ? <AppNavigator /> : <AuthNavigator />}
        </NavigationContainer>
      </AuthContext.Provider>
    </View>
  );
1 Like