SpicyClubSauce
SpicyClubSauce

Reputation: 4256

React Native AppLoading - how to stay on loading screen till local JSON file is fully imported?

In React Native, I'm loading in a local JSON file with data as an array via import (and then shuffling the array), but would somehow like this to happen in the AppLoading stage, not after the AppLoading, when I'm trying to render the main app.

In the current state, the App takes too long to read in the local JSON file AFTER the App Loading screen, not DURING (i have 'intro sliders' after the app loading screen, but before the main body of the app. Is that possible to do?

Here is my code (abbreviated):

  import React, { Component } from 'react';
  import {
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
    Image,
    Dimensions,
    Alert
  } from 'react-native';
  import { Font } from 'expo';
  import CardStack, { Card } from 'react-native-card-stack-swiper';
  import AppIntroSlider from 'react-native-app-intro-slider';

  import imagedata from './assets/cleaned_imagesdata.json'; 
  //Here is where I'm importing in data from a local JSON


  var shuffle = require('shuffle-array'),
    collection = imagedata;

  shuffle(collection);

  export default class App extends Component<{}> {
    constructor(props) {
      super(props);
      this.state = {
        fontLoaded: false,
        showRealApp: false
      };
    }

    async componentDidMount() {
      await Font.loadAsync({
        'proxima-nova': require('./assets/fonts/proxima-nova-soft-light-webfont.ttf'),
        'proxima-nova-bold': require('./assets/fonts/ProximaNovaBold.ttf')
      });

      this.setState({fontLoaded: true});
    }

    _onDone = () => {
      this.setState({showRealApp: true});
    };

    render() {

      if (!this.state.fontLoaded) {
        return <Expo.AppLoading />; //THIS IS THE PART
      }

      if (this.state.showRealApp) {
        const contents = collection.map((item, index) => {
          return (
              <Card key={index}>
                ....
              </Card>
          )
        });

        return (
            <View style={{flex:1}}>
             ....
             {contents}
             ....
            </View>
        );
      } else {
        return <AppIntroSlider slides={intro_slides} onDone={this._onDone}/>;
      }
    }
  }

I've looked at the docs for Preloading assets in Expo's AppLoading component and tried mimicking by having _loadAssetsAsync() set the JSON file/array to a variable, but this makes the loading take much longer. Is there a better way to 'read in the local JSON file as an array and preload/cache it'?

    async _loadAssetsAsync() {
      const collection = imagedata;
      await Promise.all([collection]);
    }

 render() {

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

Upvotes: 0

Views: 3455

Answers (1)

Martin Konicek
Martin Konicek

Reputation: 40904

From the expo docs it looks like your second part of the post is the way to go:

<Expo.AppLoading
      startAsync={this._loadAssetsAsync}
      onFinish={() => this.setState({ isReady: true })}

As for loading the JSON data:

import imageData from './assets/cleaned_imagesdata.json'; 
const shuffle = require('shuffle-array');
shuffle(imageData);

You should do this in your application logic, for example in _loadAssetsAsync so that React knows when it's done rather than using an import statement at the top level.

this makes the loading take much longer

How big is the JSON file you're loading? If performance is an issue, can you split it into several smaller JSON files and load the rest of the data only when it's needed, e.g. just before the user can see that data?

Upvotes: 1

Related Questions