AppLoading fetching and saving data with Redux

I need to fetch data in my app.js file but I can’t save them due to not being able to use redux in app.js

I moved all of the fetching in a component, imported it into app.js trying to get it to run in AppLoading as an async but it ends up giving me an error of undefined is not a function (near '..._ExerciseFetching.default.fetchExercises...')

app.js

render() {
    if (!this.state.isReady) {
      return (
        <AppLoading
          startAsync={async () => {
            await this._loadAssetsAsync();
            ExerciseFetching.fetchExercises(() => {
             this.setState({ isLoadingComplete: true });
            })
          }}
          onFinish={() => this.setState({ isReady: true })}
          onError={console.warn}
        />
      );
    } 

ExerciseFetching component

ExerciseFetching component file
   fetchExercises = async (props, complete) => {
        const { loadingExercises, exerciseCount, addExercise, receivedExercises } = props;

        console.log(loadingExercises, exerciseCount);

        if (exerciseCount >= 3000) {
            await receivedExercises();
            complete();
            return
        }

        await props.requestExercises();

        const url = "myURL";

        const parseBasicExercise = exercise => ({ id: exercise.id, name: exercise.Name });
        const exercises = await axios.get(url, {
            params: {
                _limit: -1
            }
        }
        ).then(resp => {
            const exercises = resp.data.map(parseBasicExercise);
            console.log("Data", exercises)
            return exercises;
        }).catch(err => {
            console.log('<> <> axios err ' + err)
        });

        exercises.forEach(async ({ id, name }) => {
            await addExercise({ id: id.toString(), name });
        });

        complete();
    }
}
  1. SDK Version: 39
  2. Platforms: android & iOS

What am I doing wrong here? I’m a noob and I have been working on this for 36hrs and I’m losing my mind. I really don’t want to implement saga as I don’t know how to use it and anything that I’ve found and have read is either vague or didn’t work.

Hey there! I’ll gladly try to help, but it may be helpful to see the entire filres for app.js and ExcerciseFetching file. Could you please provide those?

I had to repost my previous post because I had to update something.

Tired to minify the code and take out all the unused stuff as much as possible.
Thank you for helping me out

App.js

import React from 'react';
import { AppLoading } from 'expo';
import { Asset } from 'expo-asset';
import { Root, StyleProvider } from "native-base";
import { StatusBar, AppRegistry, TouchableWithoutFeedback, Keyboard } from "react-native";
import AppPreLoader from "./application/components/AppPreLoader";
import firebaseConfig from './application/utils/Firebase';
import * as firebase from 'firebase';

if (firebase.apps.length === 0) {
  firebase.initializeApp(firebaseConfig);
}

import GuestNavigation from './application/navigations/Guest';
import LoggedNavigation from './application/navigations/Logged';
import { store, persistor } from './application/redux/store';
import { PersistGate } from 'redux-persist/integration/react'
import { Provider } from 'react-redux';
import { MenuProvider } from 'react-native-popup-menu';

import ExerciseFetching from './application/components/ExerciseFetching';

// Native base theme
import getTheme from "./native-base-theme/components";
import variables from "./native-base-theme/variables/platform";


console.disableYellowBox = true;
function cacheImages(images) {
  return images.map(image => {
    if (typeof image === 'string') {
      return Image.prefetch(image);
    } else {
      return Asset.fromModule(image).downloadAsync();
    }
  });
}




export default class App extends React.Component {

  constructor() {
    super();
    this.state = {
      isLogged: false,
      loaded: false,
      isReady: false,
      isLoadingComplete: false,
    }
  }

  async _loadAssetsAsync() {
    const imageAssets = cacheImages([,
      require('./assets/images/logo.png'),
      require('./assets/images/nointernet.png'),
      require('./assets/images/contact.png'),
    ]);

    await Promise.all([...imageAssets]);


  }

  async componentDidMount() {

    await Expo.Font.loadAsync({
      Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
      ssb_Bold: require('./assets/font/Source_Sans_Pro/SourceSansPro-Bold.ttf'),
      ssb_Regular: require('./assets/font/Source_Sans_Pro/SourceSansPro-Regular.ttf'),
      ssb_Light: require('./assets/font/Source_Sans_Pro/SourceSansPro-Light.ttf'),
      ssb_SemiBold: require('./assets/font/Source_Sans_Pro/SourceSansPro-SemiBold.ttf'),
      SimpleLineIcons: require('native-base/Fonts/SimpleLineIcons.ttf'),
      Ionicons: require('native-base/Fonts/Ionicons.ttf'),
      'Material Icons': require('native-base/Fonts/MaterialIcons.ttf'),
    });

    await firebase.auth().onAuthStateChanged((user) => {
      if (user !== null) {
        this.setState({
          isLogged: true,
          loaded: true
        });
      } else {
        this.setState({
          isLogged: false,
          loaded: true
        });
      }
    })
  }

  render() {
    
    
    if (!this.state.isReady) {
      return (
        <AppLoading
          startAsync={async () => {
            await this._loadAssetsAsync();
            ExerciseFetching.fetchExercises(() => {
             this.setState({ isLoadingComplete: true });
            })
          }}
          onFinish={() => this.setState({ isReady: true })}
          onError={console.warn}
        />
      );
    }     


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

    const { isLogged, loaded, isReady } = this.state;

    if (!loaded) {
      return (
        <AppPreLoader/>
      );
    }

    if (isLogged && isReady) {
      // if (isReady) {
      return (

        <TouchableWithoutFeedback onPress={() => {
          Keyboard.dismiss()
        }}>

          <StyleProvider style={getTheme(variables)}>
            <Provider store={store}>
              <PersistGate persistor={persistor}>
                <MenuProvider>
                  <Root>
                    <StatusBar barStyle="dark-content" backgroundColor="white" />
                    <LoggedNavigation />
                  </Root>
                </MenuProvider>
              </PersistGate>
            </Provider>
          </StyleProvider>

        </TouchableWithoutFeedback>

      );
    }
    else {
      return (
        <Root>
          <StatusBar hidden />
          <GuestNavigation />
        </Root>
      );
    }
  }
}

AppRegistry.registerComponent('main', () => App);

ExerciseFetching

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addExercise, receivedExercises, requestExercises } from '../redux/actions/exerciseActions';
import axios from 'axios';

class ExerciseFetching extends Component {



    componentDidMount() {
        fetchExercises(this.props, () => this.setState({ isLoadingComplete: false}));
    }


    fetchExercises = async (props, complete) => {
        const { loadingExercises, exerciseCount, addExercise, receivedExercises } = props;

        console.log(loadingExercises, exerciseCount);

        if (exerciseCount >= 3000) {
            await receivedExercises();
            complete();
            return
        }

        console.log('<> <> loadingExercise??? ', loadingExercises)

        // Set loading true
        await props.requestExercises();

        const url = "link to the backend";

        const parseBasicExercise = exercise => ({ id: exercise.id, name: exercise.Name });
        console.log('<> <> DOING A FETCH <> <> with count ', exerciseCount);
        const exercises = await axios.get(url, {
            params: {
                _limit: -1
            }
        }
        ).then(resp => {
            const exercises = resp.data.map(parseBasicExercise);
            console.log("Data", exercises)
            return exercises;
        }).catch(err => {
            console.log('<> <> axios err ' + err)
        });

        console.log("<> <> got response pt 2" + " " + exercises.length)

        exercises.forEach(async ({ id, name }) => {
            await addExercise({ id: id.toString(), name });
        });

        complete();
    }
}


const mapDispatchToProps = (dispatch) => ({
    addExercise: (exercise) => dispatch(addExercise(exercise)),
});

export default connect(mapStateToProps, mapDispatchToProps)(ExerciseFetching);

Hi, would you have any tips on this? I sadly still can’t figure out how to get this to run

Hey,

After looking at your code, there seems to be quite a bit of fundamental React flaws here. First thing, it doesn’t seem like there is any reason you need to create a Component for ExerciseFetching, it doesn’t if have a render function. Also the way you are trying to call the fetchExercises function from App?Loading seems to be an invalid way of calling it. It looks like you’re trying to add a function to call after it finishes in AppLoading but that isn’t what is happening. You also seem to be trying to use a variable mapStateToProps in your connect HOC, but that is not defined anywhere. I would try to simplify this all, and not have this be another Component, because you’re not using it as a component.

yea putting what I had in app.js in another file and I don’t think I have set it up right.

Everything fetches and loads if I put it in home screen but the problem is the fetching causes a lag in the app for a few seconds. So I wanted to put it in my app.js to use with AppLoading so during fetching time for it to just show the splash screen but I can’t use mapStateToProps in app.js. What would you recommend?

There are many different ways you can accomplish this, one of which having your App.js only worry about the Providers, and then the only child would be another component that you import that takes care of your app loading logic which you can then handle there. another quick and dirty way you could do it here is you already have access to the store in the App.js file, so you could do something as easy as store.dispatch(myAction()) to fire off an action that you want to fire and use store.getState() to get the current state of the store. Then you wouldn’t need to wrap the component in connect. This probably wouldn’t be my first choice, but probably the quickest way to get done what you want