How to Implement API in React Native Functional Component with redux, redux-saga

Uttam Tarasariya
5 min readMay 3, 2021

In this blog, we are going to be targeting how to implement API with redux and redux-saga in the React Native Functional Component for faster execution and managing asynchronous call step by step.

Basic workflow : Application will make the http request from the functional component by dispatching an action, it will be managed by a Middleware (Redux-saga) before passing it to the reducer. After getting response, Middleware can dispatch the action with the result and reducer stores it into the redux-store.

This data will keep stored locally using a third party library called persist even though the app will close and reopen again. I will cover this thing as a saeparate blog.

Step 1. Project setup

Structure your files by following format.

Install following libraries..

// run the follwing commands for installing redux and axios for HTTP request
npm i react-redux
npm i redux
npm i redux-saga
npm i axios

Step 2 : Implement redux

Create action and reducer using which we can make the API call by dispatching the action and store it into the redux-store.
Update redux -> constants -> index.js

const FETCH_DATA = “FETCH_DATA”;
const LIST_FETCHED = “LIST_FETCHED”;
const API_CALLED = “API_CALLED”;
export const Action = { FETCH_DATA,LIST_FETCHED,API_CALLED };

Create the actions which will be dispatched from the functional component.
Update redux -> actions -> index.js

import { Action } from “../constants”;export const fetchList= () => {
return {
type: Action.FETCH_DATA,
};
};
export const storeListData= (result) => {
return {
type: Action.LIST_FETCHED,
data : result,
};
};
export const apiCalled = () => {
return {
type: Action.API_CALLED,
};
};

Create the reducer which store the data according the dispatched action.
Update redux -> reducers -> reducer.js

import { Action } from “../constants”;const initialState = {
isLoading: false,
productList: null
};
export const mainReducer = (state = initialState, action) => {
switch (action.type) {
case Action.FETCH_DATA :
return {
...state,
isLoading: true
};
break;
case Action.LIST_FETCHED :
return {
...state,
productList: action.data
};
break;
case Action.API_CALLED :
return {
...state,
isLoading: false
};
break;
default :
return state;
}
};

If we want to use multiple reducers in the application, we must have to combine them all.
Update redux -> reducers -> index.js

// if you use the multiple reducer than you have to combine it togetherimport { combineReducers } from “redux”;
import { mainReducer } from “./reducers”;
export default combineReducers({ mainReducer });

Step 3 : Create Middleware sagas
When you dispatch an action for fetching list and change the state of the app and we need to do something after that, we can use saga for that interaction before store it to redux-store.
Here, redux-saga has default function which are call, put, takeLatest, takeEvery.
call()
is used for the call to another generator function.
put() is used for the dispatch an action from generator functions to the store.
takeLatest() allows only one task at a moment and it is the latest one, if the previous one is still in progress then it will be cancelled.
takeEvery() allows multiple api calls concurrently.
(I will publish the separate blog on redux-saga which contains these methods in detail).

Update redux -> sagas -> index.js

import { call, put, takeLatest, takeEvery } from "redux-saga/effects";
import { Action } from "../constants";
import { storeListData, apiCalled } from "../actions";
// yield pauses and resume the generator functionsfunction* getProductList() {
try {
const response = yield axios.get(url,{ headers: {} });
if (response.status == 200) {
// to fire another action, use put method
// here I am storing the data by firing action LIST_FETCHED
yield put(storeListData(response.data));
// for calling another generator funtion use call method } else {
// handle other response code
}
} catch (error) {
console.log(error);
} finally {
yield put(apiCalled());
}
}
function* appSagas() {
yield takeLatest(Action.FETCH_DATA, getProductList);
}
export default appSagas;

Step 4 : Create redux store
Create a redux store and apply middleware which we just created and run that middleware.
Update redux -> sagas -> index.js

import { createStore, applyMiddleware } from “redux”;
import createSagaMiddleWare from “redux-saga”;
import rootReducer from “./reducers”;
import appSagas from “./sagas”;
// create middleware of redux-sagaconst sagaMiddleWare = createSagaMiddleWare();
const store = createStore(applyMiddleware(sagaMiddleWare));
// run saga
sagaMiddleWare.run(appSagas);
export default store;

Let’s finalize the code..
Update your app.js file by providing the store to it.

// this file will be coded as per your needs, do not copyimport { Provider } from “react-redux”;
import { NavigationContainer } from “@react-navigation/native”;
import reduxStore from “./src/redux”;
import AppNavigation from “./src/navigations”;
const App = () => {
return (
<Provider store={reduxStore}>
<NavigationContainer>
<AppNavigation />
</NavigationContainer>
</Provider>
);
};
export default App;

Here is the code, how we can call that API in our functional component.
There are two methods useSelector and useDispatch which are the same like mapStateToProps and mapDispatchToProps in the class component of the react.
useSelector() method is used when we want to get the state which is stored in the redux-store.
useDisptach() method is used when we want to dispatch any action from the functional component.

import React, { useState, useEffect } from “react”;
import { View } from "react-native";
import { useDispatch, useSelector } from “react-redux”;
import { fetchList } from “../../../redux/actions”;
const ProductListScreen = (props) => {// create dispatch first for dispatch action which make the api call
const dispatch = useDispatch();
// if you want to dispatch any action from here..
// dispatch(whateverAction());
// this is how we can get that api result
const result = useSelector((state) => state.mainReducer.productList);
const isLoading = useSelector((state) => state.mainReducer.isLoading); return (
<View />
);
}
export default ProductListScreen;

This is how we can implement API using middleware saga, and redux.
We have some API’s response,that we have to store to avoid API calls every time the app is reopened. We can do this by using persist. We will look into it in detail in the next phase.

Thank you for reading… 😊😊😊

--

--