expo AppLoading startAsync Deprecated. what is the alternative?

Viewed 1779

I am learning react native from Udemy. In one of the lessons I saw AppLoading has been used for loading fonts.

So i want to learn about it in documentation from here. I am able to use that without any issues even though, I saw here that startAsync has been deprecated.

What is the alternative to this startAsync if it stopped working?

below is the code from documentation,

import React from 'react';
import { Image, Text, View } from 'react-native';
import { Asset } from 'expo-asset';
import AppLoading from 'expo-app-loading';

export default class App extends React.Component {
  state = {
    isReady: false,
  };

  render() {
    if (!this.state.isReady) {
      return (
        <AppLoading
          startAsync={this._cacheResourcesAsync}
          onFinish={() => this.setState({ isReady: true })}
          onError={console.warn}
        />
      ); }

    return (
      <View style={{ flex: 1 }}>
        <Image source={require('./assets/snack-icon.png')} />
      </View>
    );
  }

  async _cacheResourcesAsync() {
    const images = [require('./assets/snack-icon.png')];

    const cacheImages = images.map(image => {
      return Asset.fromModule(image).downloadAsync();
    }); 
    return Promise.all(cacheImages);
  }
}
2 Answers

Call _cacheResourcesAsync function in componentDidMount and when all promised are resolved set state isReady to true like:

import React from 'react';
import { Image, Text, View } from 'react-native';
import { Asset } from 'expo-asset';
import AppLoading from 'expo-app-loading';

export default class App extends React.Component {
  state = {
    isReady: false,
  };
  componentDidMount(){
     _cacheResourcesAsync();
  }
  render() {
    if (!this.state.isReady) {
      return (
        <AppLoading />
      ); }

    return (
      <View style={{ flex: 1 }}>
        <Image source={require('./assets/snack-icon.png')} />
      </View>
    );
  }

   _cacheResourcesAsync() {
    const images = [require('./assets/snack-icon.png')];

    const cacheImages = images.map(image => {
      return Asset.fromModule(image).downloadAsync();
    }); 
    Promise.all(cacheImages).then(()=>{
       this.setState({ isReady : true });
    });
  }
}

You should use a hook to load your images.

First, create a hook to load resources in a separate file:

import * as SplashScreen from 'expo-splash-screen';
import { useEffect, useState } from 'react';

export default function useCachedResources() {
  const [isLoadingComplete, setLoadingComplete] = useState(false);

  // Load any resources or data that we need prior to rendering the app
  useEffect(() => {
    async function loadResourcesAndDataAsync() {
      try {
        SplashScreen.preventAutoHideAsync();

        // Load images
        const images = [require('./assets/snack-icon.png')];
        await images.map(async image =>
          await Asset.fromModule(image).downloadAsync()); 
      } catch (e) {
        // We might want to provide this error information to an error reporting service
        console.warn(e);
      } finally {
        setLoadingComplete(true);
        SplashScreen.hideAsync();
      }
    }

    loadResourcesAndDataAsync();
  }, []);

  return isLoadingComplete;
}

Then call it in your App component - I changed it to a function component, because hooks don't work in classes and it is now the recommended way of coding react:

import { Image, View } from 'react-native';
import useCachedResources from "./hooks/useCachedResources";

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

    if (!isLoadingComplete) {
        return null;
    }

    return (
      <View style={{ flex: 1 }}>
        <Image source={require('./assets/snack-icon.png')} />
      </View>
    );
}
Related