Fetching data from API in react native using redux

pranami

I am working on a react-native project where I am trying to fetch data from an api using axios library and display the data.So,my app first shows a splash screen and it then needs to navigate to a page which consists of tabs.The tabs will contain the data from the api.

So,I am trying to initialize my store in my Homepage which comes after the splash screen.I have my reducer and action defined separately in 2 different files.

App.js file

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
import SplashScreen from './src/components/SplashScreen';
import HomeScreen from './src/components/HomeScreen';

const Navigation = StackNavigator({
    Splash: {
      screen: SplashScreen
    },
    Home: {
      screen: HomeScreen
    }
})

export default Navigation;

My SplashScreen component:

import React from 'react';
import { StyleSheet,
         Text,
         View,
         } from 'react-native';

export default class SplashScreen extends React.Component {
  static navigationOptions = {
    header: null
  }

  componentWillMount() {
    setTimeout(() => {
      this.props.navigation.navigate('Home')
    },2000)
  }

  render() {
    return(
        <View style={styles.container}>
          <Text style={styles.welcome}>Splash Screen</Text>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'skyblue'
  },
  welcome: {
    color: '#FFF',
    fontSize: 30
  }
})

My HomeScreen component:

import React from 'react';
import { StyleSheet,
         Text,
         View,
         } from 'react-native';

export default class SplashScreen extends React.Component {
  static navigationOptions = {
    header: null
  }

  componentWillMount() {
    setTimeout(() => {
      this.props.navigation.navigate('Home')
    },2000)
  }

  render() {
    return(
        <View style={styles.container}>
          <Text style={styles.welcome}>Splash Screen</Text>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'skyblue'
  },
  welcome: {
    color: '#FFF',
    fontSize: 30
  }
})




import React from 'react';
import { StyleSheet,
         Text,
         View,
         } from 'react-native';

export default class SplashScreen extends React.Component {
  static navigationOptions = {
    header: null
  }

  componentWillMount() {
    setTimeout(() => {
      this.props.navigation.navigate('Home')
    },2000)
  }

  render() {
    return(
        <View style={styles.container}>
          <Text style={styles.welcome}>Splash Screen</Text>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'skyblue'
  },
  welcome: {
    color: '#FFF',
    fontSize: 30
  }
})

Action.js file

import axios from 'axios';
export const FETCH_DATA = 'fetch_data';

const API = 'https://api.myjson.com/bins/fz62x';

export function fetchData() {
  const request = axios.get(API);

  return dispatch => {
    return request.then((data) => {
        dispatch({
          type: FETCH_DATA,
          payload: data
        })
    })
  }
}

My reducer

import { FETCH_DATA } from './actions';

export default function(state={}, action) {
  switch(action.type) {
    case FETCH_DATA:
      return {
        ...state,
        action.payload
      };

    default:
        return state;
  }
}

Can anyon please tell me if this the correct way? If not, then what is the correct way?

Ivalo Pajumets

I would say there is no correct or incorrect way to do this. But I can share kind of a pattern that I usually use.

First I would create separate folders for different files. Actions in actions folder, reducers in reducers folder etc... I would create separate constants.js file and configureStore.js file and put them inside the project root directory.

I would drop Axios library and would just use Fetch API for data fetching. Considering your code I would do the following.

Create configureStore.js file inside your project root directory. I recommend you to use Redux-Thunk. You can find more info from here.

configureStore.js

import { createStore, applyMiddleware } from 'redux';
import app from './reducers';
import thunk from 'redux-thunk';

export default function configureStore() {
    let store = createStore(app, applyMiddleware(thunk))
    return store
}

App.js

import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { StackNavigator } from 'react-navigation';
import configureStore from './configureStore';
import HomeScreen from './screens/HomeScreen';

const NavigationApp = StackNavigator({
    HomeScreen: { screen: HomeScreen }
})

const store = configureStore()

export default class App extends Component {

    render() {
        return (
            <Provider store={store}>
                <NavigationApp />
            </Provider>
        );
    }
}

Let's create constants.js and we place it inside the project root directory.

constants.js

export const FETCHING_TODOS = 'FETCHING_TODOS';
export const FETCH_TODOS_SUCCESS = 'FETCH_TODOS_SUCCESS';
export const FETCH_TODOS_FAILURE = 'FETCH_TODOS_FAILURE';

Now let's move on and create our action file which would be put inside the actions folder. Let's name it something like fetchToDos.js. Let's create a simple function using Fetch API.

fetchToDos.js

import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';

export function fetchToDos() {

    return (dispatch) => {
        dispatch(getTodos())

        return(fetch('https://api.myjson.com/bins/fz62x'))
        .then(res => res.json())
        .then(json => {

            return(dispatch(getToDosSuccess(json)))
        })
        .catch(err => dispatch(getToDosFailure(err)))
    }
}

function getToDos() {

    return {
        type: FETCHING_TODOS
    }
}

function getToDosSuccess(data) {

    return {
        type: FETCH_TODOS_SUCCESS,
        data
    }
}

function getToDosFailure() {
    return {
        type: FETCH_TODOS_FAILURE
    }
}

fetchToDos.js with Axios

import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
import axios from 'axios';

export function fetchToDos() {

    return (dispatch) => {
        dispatch(getUser())
        axios.get('https://api.myjson.com/bins/fz62x')
            .then(function (response) {

                // handle your response here, create an object/array/array of objects etc... 
                // and return it in dispatch(getToDosSuccess(data over here))

                return(dispatch(getToDosSuccess(response.data)))
            })
            .catch(err => dispatch(getToDosFailure(err)))
    }
}

// rest is the same...

Moving on to reducers. Let's create two files - index.js, todos.js and put them inside reducers folder.

todos.js

import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';

const initialState = {
    todos: [],
    isFetching: false,
    error: false
}

export default function todosReducer(state = initialState, action) {

    switch(action.type) {
        case FETCHING_TODOS:
            return {
                ...state,
                isFetching: true
            }
        case FETCH_TODOS_SUCCESS:
            return {
                ...state,
                isFetching: false,
                todos: action.data
            }
        case FETCH_TODOS_FAILURE:
            return {
                ...state,
                isFetching: false,
                error: true
            }
        default:
            return state
    }
}

index.js

import { combineReducers } from 'redux';
import todos from './todos';

const rootReducer = combineReducers({
    todos
})

export default rootReducer

Basically "heavy lifting" is done. I would only create one screen because let's assume that users would tap back button (Android) while at home screen, they would end up on that splash screen. So in this example I am going to use one screen only.

HomeScreen.js

import React, { Component } from 'react';
import {
    View,
    Text,
    ActivityIndicator
} from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { fetchTodos } from '../actions/fetchTodos';

class HomeScreen extends Component {

    componentDidMount() {

        this.props.fetchTodos()

    }

    render() {

        const { todos, isFetching } = this.props.todos

        if (isFetching) {
            return(
                <View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
                    <ActivityIndicator size={'large'} /> 
                </View>
            )
        } else {
            return(
                <View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
                    <Text>todos.length</Text>
                </View>
            )
        }

    }

}

function mapStateToProps(state) {
    return {
        todos: state.todos
    }
}

function mapDispatchToProps(dispatch) {
    return {
        ...bindActionCreators({ fetchTodos }, dispatch)
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen)

I really hope that you find this concept useful because I can say from my experience that it helped me a lot when I first get started and it helped me to understand the whole concept of redux much better.

Sorry if there are any typos and errors. I was on a flow.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Need help fetching data from API and displaying it, React-Redux thunk

React : Fetching data from inputs using createRef

React Redux fetching data from backend approach

Fetching data from api in react

Fetching list of objects from API react native

React native Fetching and using usestate for dependant data items

Fetching data from Api in Reactjs using Axios

Fetching Data From Server Using iOS Device in React Native

Fetching data from facebook using graph api

How to fetching data JSON using react-native-dropdown?

setState not working in react native after fetching data from database

React Router Fetching data from API

App Fetching slowly large number of data from firebase react native

Fetching data from api and passing it to state in React

Fetch data from API using React Native

React Native fetching data from Firebase does not work

Fetching Data from API using UseEffect

Fetching data from YouTube API with React Hooks

React: following DRY in React when fetching data from API

Fetching data from api promise in react API

Problem with fetching data to React Native application from express server

Fetching API data with React

Data's not displaying while fetching from API and using Flatlist in react native

Unable to view data in react native using Axios from an API

fetching data using redux

Fetching data from nested array in API React Native

fetching nested data from rest countries API using typescript in react

React fetching Data from Node Server using fetch() API

Fetching data from an API using the Fetch API in HTML with JavaScript