|

How to do API calls in React Native with Axios and Redux

Redux is the most popular application state management library used in react as well as react native apps. In this blog post, I will explain to you how to do API calls or HTTP requests in react native with redux and Axios.

Update: Check out my new blog post on how to do API calls in react native with axios, redux and hooks.

Here, I am not going to talk about redux and its advantages, I hope you know the basic of the redux library. If you are just starting with redux then this article will be a nice fit for you to start with.

In this react-native redux Axios example, I will be using five libraries- redux, react-redux, redux-thunk, redux-logger and Axios.

Redux

As I mentioned redux is a predictable state container which helps you to develop applications which behave consistently. Redux can be installed using the command given below.

npm install –save redux

React Redux

This library makes the redux usable or react and react native applications. This library is from the same team of redux and it is designed to work with the component model. React redux can be installed using the following command:

npm install react-redux

Redux Thunk

This library makes the actions of redux asynchronous. It is a middleware for Redux and can be used well for async actions such as HTTP requests. Still thinking what is a thunk? Then check out this article. Redux thunk can be installed using the command given below.

npm install redux-thunk

Redux Logger

As the name indicates, it’s a logging tool middleware for redux. This library helps you to track down what’s happening with redux while developing your app. Install redux logger using the following command:

npm i –save redux-logger

Axios

It’s a promise based http client to make api calls inside the app. You can install Axios using the following command:

npm install axios

That’s it. Add these libraries in your react native project and let’s move to the code section.

Apart from the App.js file, create files named ActionCreator.js, Action.js, ActionTypes.js, Reducer.js, Store.js, and Home.js.

Action creators are functions which helps us to create actions. Following is the code of ActionCreator.js. As you see, here we have a function which returns a promise using Axios library. We are also dispatching actions which are imported from Action.js file.

import axios from 'axios';
import { fetchData, fetchSuccess, fetchError } from "./Action";

const actionCreator = url => dispatch => {
  return new Promise(() => {
    axios
      .get(url)
      .then(response => {
        dispatch(fetchSuccess(response.data));
      })
      .catch(error => {
        dispatch(fetchError(error));
      });
  });
};

export default actionCreator;

Following is the code of Actions.js. By dispatching actions, you let know the reducer about the data changes. We have separate actions when the API request is pending, success and failure.

import ACTION_TYPES from './ActionTypes.js';

export const fetchData = () => ({
  type: ACTION_TYPES.API_PENDING
});

export const fetchSuccess = data => ({
  type: ACTION_TYPES.API_SUCCESS,
  payload: data
});

export const fetchError = error => ({
  type: ACTION_TYPES.API_ERROR,
  payload: error
});

ActionTypes.js is the file where we defined different action type names.

const ACTION_TYPES = {
  API_PENDING: 'SERVICE_PENDING',
  API_SUCCESS: 'SERVICE_SUCCESS',
  API_ERROR: 'SERVICE_ERROR',
};
export default ACTION_TYPES;

Following is the code of Reducer.js. Reducers handle how the state changes in response to the sent actions. Initially, the data and error in the state are empty for us. This would change once the actions are dispatched.

import ACTION_TYPES from './ActionTypes';

const initialState = {
  data: '',
  error: ''
};

const apiReducer = (state = initialState, action) => {
  switch (action.type) {
    case ACTION_TYPES.API_PENDING:
      return {
        ...state
      };
    case ACTION_TYPES.API_SUCCESS:
      return {
        ...state,
        data: action.payload
      };
    case ACTION_TYPES.API_ERROR:
      return {
        ...state,
        error: action.payload
      };

    default:
      return state;
  }
};

export default apiReducer;

Store.js is where the state of the whole mobile app is stored. createStore is used to create the store whereas applyMiddleware is used to utilize middlewares such as redux-thunk and redux logger.

import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';
import apiReducer from './Reducer';

const appReducers = combineReducers({
  apiReducer,
});

const rootReducer = (state, action) => appReducers(state, action);

const logger = createLogger();

let middleware = [];
middleware = [...middleware, thunk, logger];

export default createStore(
  rootReducer,
  compose(applyMiddleware(...middleware))
);

Home.js is the main screen of this react native-redux-axios example. It has a FlatList component which gets data from an API. We use action creators to do API call and we get data from the app state using apiReducer.

import React, { Component } from 'react';
import { View, Text, FlatList } from 'react-native';
import { connect } from "react-redux";
import apiCall from "./ActionCreator";

class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: ''
    };
  }

  componentDidMount() {
    this.props
      .apiCall("https://jsonplaceholder.typicode.com/posts")
      .then(() => {
        const data = this.props.data;
        this.setState({
          data,
        });
      })
      .catch(error => {
        console.log(error);
      });
  }

  render() {
    return (
      <View style={{ flex: 1, backgroundColor: 'white' }}>
        <FlatList
          data={this.props.data}
          renderItem={({ item }) => <Text>{item.title}</Text>}
          keyExtractor={(item, index) => index.toString()}
        />
      </View>
    );
  }
}

const mapDispatchToProps = dispatch => ({
  apiCall: url => dispatch(apiCall(url))
});

const mapStateToProps = state => ({
  data: state.apiReducer.data,
  error: state.apiReducer.error,
});

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

Now, the final step is to wrap the whole app with provider so that we can use redux anywhere inside the app. So change App.js file as given below:

import React, { Component } from "react";
import { Provider } from "react-redux";
import Store from "./Store";
import Home from "./Home";

export default class App extends Component {
  render() {
    return (
      <Provider store={Store}>
        <Home />
      </Provider>
    );
  }
}

That’s it. Run the react native project with the remote debugging enabled and you can track the data from redux in the console.

react native redux api example

I have created a Github repository for this react native redux example, you can check it out here.

Similar Posts

One Comment

  1. Hi Rashid,

    Thanks for your simple example. I tried to run your example on my Android emulator. But, when I ask for a request the JSON data, the Home.js class code work before data is filling the this.props.data. For this reason, in render() func the “this.props.data” property shows empty string. As I meant that this code part in below:

    render() {
    debugger;
    console.log(this.state.data)

    return (

    {item.Text}}
    keyExtractor={(item, index) => index.toString()}
    />

    )
    }

    I also try to write down “this.state.data” property. It is also empty string.

    That’s why my emulator shows me a White screen on it.

    Have you got any idea about that?

    Thanks in advance.

Leave a Reply