When and How To Load Data from API

Hi there,

I’m new to this platform, so please be gentle.

I’ve started an an app using Expo. The template I chose has an App.js file with some screens.

I’ve modified this template to utilize Redux state, doing some provider wrapping like this:

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

  if (!isLoadingComplete && !props.skipLoadingScreen) {
    return (
      <AppLoading
        startAsync={loadResourcesAsync}
        onError={handleLoadingError}
        onFinish={() => handleFinishLoading(setLoadingComplete)}
      />
    );
  } else {
    return (
      <Provider store={store}>
        <View style={styles.container}>
          <CustomStatusBar />
          <AppNavigator />
        </View>
      </Provider>
    );
  }
}

During the loading process, I want to make some API calls to load data into Redux state.

In a React app (non-native), I would do this in index.js, which doesn’t exist in this setup.

To be clear, the data being retrieved by the API will be used across any page of the app, and I want this data to be loaded before any screen is loaded.

Question:
What is the best pattern to accomplish this?

Thanks.

Hi :slight_smile: I’m new here too.

I see you are using useState, so I assume you have certain knowledge about React Hooks.

Basically, you just need to use UseEffect like this:

const [isLoadingComplete, setLoadingComplete] = useState(false);

useEffect(() =>{
    loadYourData()
     .then(data => saveToYourStore(data))
     .then(() => setLoadingComplete(true))
     .catch(e => doSomeThingDealwithException())
}, [])

//your render stuff...
1 Like

You can think of App.js in an Expo app as index.js in the code you’ve worked on previously. It is basically the entry point to your app.

1 Like

Thanks for the advice, @pxmage and @wodin.

After toying with this, it appears that the loadResourcesAsyc function is where is should be making my initial API calls. This is part of the <Apploading> component and is set with the startAsync param.

So, basically, something like this (though I’ll need to catch errors at some point):

const loadResourcesAsync = async () => {
  await Promise.all([
    Asset.loadAsync([
      require("./assets/images/robot-dev.png"),
      require("./assets/images/robot-prod.png")
    ]),
    Font.loadAsync({
      // This is the font that we are using for our tab bar
      ...Ionicons.font,
      // We include SpaceMono because we use it in HomeScreen.js. Feel free to
      // remove this if you are not using it in your app
      "space-mono": require("./assets/fonts/SpaceMono-Regular.ttf")
    })
  ]);

// do API calls here
  await store.dispatch(getUserDataFromDb(currentUser));
}

Then when the promises resolve, the onFinish calls handleFinishLoading(setLoadingComplete), which sets the loadingComplete var in state to true, which will then run the else block, ultimately loading the app, instead of <Apploading>.

That’s at least how the logic works in the template that was created when I initialized expo, which is fine for now.

Thanks again for the advice.

1 Like

Thank you! Your solution really helped me! :hugs: