Create a global loading progress indicator in react

Contemporarily, It is very easy to build a web application using Javascript Frame. In these frameworks, it is quite easy to fetch data from a remote source or consume a API.

React is the one of the most popular frontend framework out there.While learning React, you will eventually get to a point when you need to integrate APIs in your React application.Fetching data from  API, let us know how to successfully communicate with information from a remote source using Axios.

We will be building a simple  application that display global loading progress bar. We will make use of this endpoint, it contains a JSON dump of data needed for our contact list application.

                                            . . .

Finally, let’s hook this up to React BoilerPlate. Its is  A highly scalable, offline-first foundation with the best developer experience and a focus on performance and best practices of a web application.

First, let’s create a React Boilerplate component to keep track of the loading state. 

Run command

Npm run generate

Select container  option and name it MyLoader

Inside the Myloader component, we are going to define its actions.

We will be a create two dispatchable action for start and stop our loader.

https://gist.github.com/goelshobhit/e6e0f4ef019c5c7d045bde1ac6a8c628.js

Inside its index.js file, we simply call a material dialog and in the dialog content, we render the material circular loader.

To install and save in your package.json dependencies, run:

// with npm

npm install @material-ui/core

// with yarn

yarn add @material-ui/core

Please note that react >= 16.8.0 and react-dom >= 16.8.0 are peer dependencies.

https://gist.github.com/goelshobhit/f93b380a15c882d5ef447db928b73736

Our UI is ready now :D

Now, we are going to  setup “MyLaoder” container. We created two actions, now we are going to use them.

Inside the container reducer, we initial declare a state, which controls the render view of the container and name its “ show loader”

 

https://gist.github.com/goelshobhit/68a590000d7a7826590cff3436df551f

Inside the selector , we will select our state.

import { createSelector } from 'reselect';

import { initialState } from './reducer';

/**

* Direct selector to the myLoader state domain

*/

const selectMyLoaderDomain = state => state.myLoader || initialState;

/**

* Other specific selectors

*/

/**

* Default selector used by MyLoader

*/

const makeSelectMyLoader = () =>

 createSelector(

   selectMyLoaderDomain,

   substate => substate,

 );

const makeSelectShowMyLoader = () =>

 createSelector(

   selectMyLoaderDomain,

   substate => substate.showLoader,

 );

export default makeSelectMyLoader;

export { selectMyLoaderDomain, makeSelectShowMyLoader, makeSelectMyLoader };

Previously we have our function , which controls the flow of our dialogue. As we control the container from state. So  no more worries about them. Perform a small cleanUp in index.js file of “myLoader” container.

/**

*

* MyLoader

*

*/

import React, { memo } from 'react';

import PropTypes from 'prop-types';

import { connect } from 'react-redux';

import { createStructuredSelector } from 'reselect';

import { compose } from 'redux';

import Dialog from '@material-ui/core/Dialog';

import DialogContent from '@material-ui/core/DialogContent';

import DialogTitle from '@material-ui/core/DialogTitle';

import Slide from '@material-ui/core/Slide';

import CircularProgress from '@material-ui/core/CircularProgress';

import { useInjectSaga } from 'utils/injectSaga';

import { useInjectReducer } from 'utils/injectReducer';

import { makeSelectMyLoader, makeSelectShowMyLoader } from './selectors';

import reducer from './reducer';

import saga from './saga';

const Transition = React.forwardRef(function Transition(props, ref) {

 return <Slide direction="up" ref={ref} {...props} />;

});

export function MyLoader({ show }) {

 useInjectReducer({ key: 'myLoader', reducer });

 useInjectSaga({ key: 'myLoader', saga });

 return (

   <div>

     <Dialog

       open={show}

       TransitionComponent={Transition}

       aria-labelledby="alert-dialog-slide-title"

       aria-describedby="alert-dialog-slide-description"

     >

       <DialogTitle id="alert-dialog-slide-title">Please wait</DialogTitle>

       <DialogContent

         style={{

           padding: '24px',

           display: 'flex',

           alignItems: 'center',

           justifyContent: 'center',

           width: '100%',

           height: '100%',

         }}

       >

         <CircularProgress />

       </DialogContent>

     </Dialog>

   </div>

 );

}

MyLoader.propTypes = {

 ...MyLoader,

};

const mapStateToProps = createStructuredSelector({

 myLoader: makeSelectMyLoader(),

 show: makeSelectShowMyLoader(),

});

function mapDispatchToProps(dispatch) {

 return {

   dispatch,

 };

}

const withConnect = connect(

 mapStateToProps,

 mapDispatchToProps,

);

export default compose(

 withConnect,

 memo,

)(MyLoader);

Now We have to call our API.

But this time its little bit different.

We are going to use axios and axios intercerptor.

SAGA.JS

import { call, takeLatest, put } from 'redux-saga/effects';

import request from 'utils/request';

import { LOAD_DATA } from './constants';

import { loadDataSuccess } from './actions';

function* data() {

 try {

   const options = {

     method: 'GET',

     url: `http://api.icndb.com/jokes/random?firstName=John&amp;lastName=Doe`,

   };

   const res = yield call(request, options);

   yield put(loadDataSuccess(res));

 } catch (e) {

   // do nthing

 }

}

// Individual exports for testing

export default function* myLoaderSaga() {

 // See example in containers/HomePage/saga.js

 yield takeLatest(LOAD_DATA, data);

}

AS soon as the Axios knows to fetch the data. We have to dispatch a actions in axios interceptor. But the problem is that how to dispatch action in request.

Let go to store and perform small amount of changes.

Declare a variable.

export let configuredStore;

….

In the end of the file .

 configuredStore = store;

 return configuredStore;

Assign this variable to the store and return this as a store variable.

Now we can import this configedStore , anywhere in the architecture  and use all the feature of our react-redux store.

import { configuredStore } from '../configureStore';

In order to dispatch action in the axios interceptor. We have to import the actions of “My loader container” inside it.

import { stopLoader, startLoader } from '../containers/MyLoader/actions';

We have to dispatch our start loader action, as soon as we call the api, means in request instance of axios.

axiosInstance.interceptors.request.use(

 config => {

   configuredStore.dispatch(startLoader());

   return config;

 },

In case of we get response from the api or we get error while calling the api we have to dispatch our “stoploader” action.

axiosInstance.interceptors.request.use(

 config => {

   configuredStore.dispatch(startLoader()); // when we call the api

   return config;

 },

 err => { 

   configuredStore.dispatch(stopLoader());  // request error handle

   return Promise.reject(err);

 },

);

axiosInstance.interceptors.response.use(

 response => {

   configuredStore.dispatch(stopLoader()); // when we get api response

   if (response.data) return response.data;

   return response;

 },

 err => {

   if (!err.response) configuredStore.dispatch(stopLoader()); // when we donot get any response

   return Promise.reject(err);

 },

);

That it. We completed our task.

Conclusion

In this post, we have only used Axios to make a GET request and obtain contents from an API. Axios is powerful enough to handle other HTTP request methods such as POST, PUT, PATCH and DELETE anywhere in our application. Feel free to improve on this and if you found this post useful, show some love with claps.

Comments :

Post a Comment

Heroku Deployment of New RBP (react-boilerplate-cra-template)

How to deploy new react-boilerplate-cra-template      RBP community ask for help, in order to deploy their lastest code to heroku server. There are two ways to do this: First way run this command npx create-react-app --template cra-template-rb my-app create a procfile web: npm run start:prod run command, heroku create, using heroku cli run basic git commit command run git push heroku master it got deployed on heroku server.  demo:  https://polar-peak-91443.herokuapp.com/ Second way: I just update the package.json file from  rbp git.. Add the heroku  procfile and run heroku command. it works fine :) demo:  https://calm-basin-19770.herokuapp.com/

Interested to get more of our Update !