Implementing a React Progress Bar Managed Through Redux

Using <TopBarProgress /> for easy progress bar mounting

React apps are static, therefore any update made to the data being displayed will involve a fetch request to a backend service (or incoming data packets from an open socket connection), but in this brief moment the app will be waiting for that data to return to the client. A progress bar is needed — which can easily be linked with your Redux state management to either show or hide the progress bar. In this article we will be visiting how this is implemented in React.

A Little About Progress Bars

A progress bar is a singleton and should only be mounted once within your DOM. This makes sense since there is only one App object — e.g. there are not multiple apps running in one browser window. In the event that the browser is split into two or more isolated UIs, there may be a use case for multiple progress bars, although this scenario is probably only likely for complex CMSs — and then you would probably opt for loader animations within that UI space.

Progress bars are typically fixed at the top of the client’s browser window and animate in various ways to indicate that the page is waiting for something to happen.

React TopBar Progress Indicator

For this article we will be using the React TopBar Progress Indicator package, found at the following NPMJS url:

https://www.npmjs.com/package/react-topbar-progress-indicator

For such a small component it is rather popular, peaking at around 15,000 weekly downloads at the time of this writing.

Install it with the following NPM command:

npm install react-topbar-progress-indicator

Our project is now ready to handle this handy UI component.

This component works in a very simple manor. If we mount it, e.g. render it’s component, the bar will appear and start to animate. If we unmount it, it will complete its animation and fade out.

What animation to use?

The animation this component adopts is a rather basic width expansion that incremently slows down until it is crawling at a snails pace. Upon unmounting the progress bar, it quickly snaps to a 100% width and fades out. This is one type of progress animation — you may notice websites like Medium opt for a continuous fast-paced loader that loops until the representative task is completed. This faster paced animation may give you the perception that your page loaded faster — but the style of animation is ultimately up to you.

Back to our progress bar. We can invoke it with the <TopBarProgress /> component within a component’s render:

import TopBarProgress from "react-topbar-progress-indicator";...   render() {
return(<TopBarProgress />)
}
...

Pretty simple, right? We can expand this and link it to a Redux setup. How would we quickly and efficiently do this?

  1. Create a ProgressBar.js component that passes the status of the progress bar from Redux into the component. This will determine whether the progress bar is mounted.
  2. Import ProgressBar.js into App.js (your top-most component) and render it on every page load.
  3. Configure Redux action and reducer.
    Within other components, import a Redux action, e.g. handleProgressBar, with an isOpen boolean which will determine open or closed.
    Configure a reducer to update your app state when handleProgressBar is called.

Let’s go through these steps.

1. Configuring ProgressBar.js

Below is the complete ProgressBar script for this example, whose responsibility is to mount or unmount the <TopProgressBar /> component. Let’s take a look at this script:

As you can see, Redux has been imported, and is passing the status of my progress bar from state.ui.progressBarStatus. This is done within a container component named HandleProgressBar. From here, we either render <TopProgressBar /> or not in our presentational component render.

2. Importing ProgressBar into App.js

As I mentioned above, your progress bar will be present throughout your entire app, therefore it should be placed outside of your navigation — maybe a React Router Switch config. For visual clarity, this is how we would place our ProgressBar:

...
import { HandleProgressBar } from "./ProgressBar";

class App extends Component {
render() { const { cookies } = this.props; return (
<div>
<HandleProgressBar />

<Switch>
<Route />
<Route />
</Switch>
</div>
)
}

Remember, there cannot be 2 top-most components, therefore we wrap the progress bar and routing in a parent <div> element. Now our progress bar is ready to be toggled.

3. Configuring Redux Action and Reducer

Adding a boolean to a Redux state tree is straight forward, so let’s quickly visit how this is done for the progress bar, starting with an action:

actions/index.js:

...export const setProgressBar = (isOpen) => (
{
type: 'SET_PROGRESS_BAR',
isOpen: isOpen
});
...

My SET_PROGRESS_BAR action is responsible for passing the isOpen bool to my reducer.

reducers/ui.js:

export const ui = (state = {}, action) => {  switch (action.type) {    case 'SET_PROGRESS_BAR':
return Object.assign({}, state, { progressBarStatus: action.isOpen });

default:
return state;
}
};
export default ui

And this is our progress bar setup in its entirety.

Bar Style

We also have access to some bar styling options, all documented from the Config section of the package’s NPMJS page. The ability to add multiple colours adds personalisation to the bar, in addition to shadow, shadow blur and thickness options.

Programmer and Author. Director @ JKRBInvestments.com. Creator of LearnChineseGrammar.com for iOS.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store