DEV Community

Joseph Nelson
Joseph Nelson

Posted on

Advanced Loading Bar System with react-redux-loading-bar in React

react-redux-loading-bar is a Redux-based loading bar component for React applications. It provides a top-loading bar that automatically shows progress for async operations managed through Redux actions, making it ideal for applications using Redux for state management. This guide walks through advanced usage of react-redux-loading-bar with React and Redux, including middleware integration, custom configurations, and complex loading patterns. This is part 51 of a series on using react-redux-loading-bar with React.

Demo animation

Prerequisites

Before you begin, make sure you have:

  • Node.js version 14.0 or higher installed
  • npm, yarn, or pnpm package manager
  • A React project (version 16.8 or higher) or create-react-app setup
  • Redux and React-Redux installed and configured
  • Basic knowledge of Redux (actions, reducers, middleware)
  • Understanding of React hooks (useSelector, useDispatch)
  • Familiarity with async operations and Redux middleware

Installation

Install react-redux-loading-bar and Redux dependencies:

npm install react-redux-loading-bar react-redux redux
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add react-redux-loading-bar react-redux redux
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add react-redux-loading-bar react-redux redux
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "react-redux-loading-bar": "^5.0.0",
    "react-redux": "^8.0.0",
    "redux": "^4.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

Set up Redux store with loading bar reducer and middleware. First, create the Redux store:

// src/store/index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { loadingBarReducer } from 'react-redux-loading-bar';
import thunk from 'redux-thunk';

const rootReducer = combineReducers({
  loadingBar: loadingBarReducer
});

export const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
Enter fullscreen mode Exit fullscreen mode

Now set up the provider and loading bar component:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store';
import LoadingBar from 'react-redux-loading-bar';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <LoadingBar />
      <App />
    </Provider>
  </React.StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

First Example / Basic Usage

Let's create a simple loading bar example. Create a new file src/LoadingBarExample.jsx:

// src/LoadingBarExample.jsx
import React from 'react';
import { useDispatch } from 'react-redux';
import { showLoading, hideLoading } from 'react-redux-loading-bar';

function LoadingBarExample() {
  const dispatch = useDispatch();

  const handleLoad = async () => {
    dispatch(showLoading());
    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 2000));
    } finally {
      dispatch(hideLoading());
    }
  };

  return (
    <div style={{ padding: '20px' }}>
      <h2>Loading Bar Example</h2>
      <button
        onClick={handleLoad}
        style={{
          padding: '10px 20px',
          backgroundColor: '#007bff',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}
      >
        Start Loading
      </button>
    </div>
  );
}

export default LoadingBarExample;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import LoadingBarExample from './LoadingBarExample';
import './App.css';

function App() {
  return (
    <div className="App">
      <LoadingBarExample />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Understanding the Basics

react-redux-loading-bar uses Redux for state management:

  • loadingBarReducer: Redux reducer that manages loading state
  • showLoading action: Dispatches to show the loading bar
  • hideLoading action: Dispatches to hide the loading bar
  • LoadingBar component: Renders the loading bar UI
  • Middleware integration: Can integrate with Redux middleware for automatic loading

Key concepts for advanced usage:

  • Redux Integration: Loading state is managed through Redux store
  • Action Dispatching: Use showLoading and hideLoading actions
  • Middleware: Integrate with Redux middleware for automatic loading bar management
  • Multiple Requests: Handles multiple concurrent requests
  • Customization: Styling and behavior can be customized

Here's an example with middleware integration:

// src/store/index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { loadingBarReducer } from 'react-redux-loading-bar';
import thunk from 'redux-thunk';

// Custom middleware for automatic loading bar
const loadingBarMiddleware = store => next => action => {
  if (action.type.endsWith('_PENDING')) {
    store.dispatch({ type: 'SHOW_LOADING_BAR' });
  } else if (action.type.endsWith('_FULFILLED') || action.type.endsWith('_REJECTED')) {
    store.dispatch({ type: 'HIDE_LOADING_BAR' });
  }
  return next(action);
};

const rootReducer = combineReducers({
  loadingBar: loadingBarReducer
});

export const store = createStore(
  rootReducer,
  applyMiddleware(thunk, loadingBarMiddleware)
);
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build a comprehensive loading system with Redux actions and middleware:

// src/actions/loadingActions.js
import { showLoading, hideLoading } from 'react-redux-loading-bar';

export const startLoading = () => (dispatch) => {
  dispatch(showLoading());
};

export const stopLoading = () => (dispatch) => {
  dispatch(hideLoading());
};

export const fetchData = () => async (dispatch) => {
  dispatch(showLoading());
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data });
    return data;
  } catch (error) {
    dispatch({ type: 'FETCH_DATA_ERROR', payload: error.message });
    throw error;
  } finally {
    dispatch(hideLoading());
  }
};
Enter fullscreen mode Exit fullscreen mode

Create a component that uses the loading bar:

// src/AdvancedLoadingSystem.jsx
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { showLoading, hideLoading } from 'react-redux-loading-bar';
import LoadingBar from 'react-redux-loading-bar';

function AdvancedLoadingSystem() {
  const dispatch = useDispatch();
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  const handleSingleRequest = async () => {
    dispatch(showLoading());
    try {
      await new Promise(resolve => setTimeout(resolve, 2000));
      setData('Single request completed');
    } catch (err) {
      setError(err.message);
    } finally {
      dispatch(hideLoading());
    }
  };

  const handleMultipleRequests = async () => {
    dispatch(showLoading());
    try {
      // Simulate multiple concurrent requests
      await Promise.all([
        new Promise(resolve => setTimeout(resolve, 1000)),
        new Promise(resolve => setTimeout(resolve, 1500)),
        new Promise(resolve => setTimeout(resolve, 2000))
      ]);
      setData('Multiple requests completed');
    } catch (err) {
      setError(err.message);
    } finally {
      dispatch(hideLoading());
    }
  };

  const handleSequentialRequests = async () => {
    dispatch(showLoading());
    try {
      await new Promise(resolve => setTimeout(resolve, 1000));
      await new Promise(resolve => setTimeout(resolve, 1000));
      await new Promise(resolve => setTimeout(resolve, 1000));
      setData('Sequential requests completed');
    } catch (err) {
      setError(err.message);
    } finally {
      dispatch(hideLoading());
    }
  };

  return (
    <div style={{ padding: '20px' }}>
      <LoadingBar
        style={{
          backgroundColor: '#007bff',
          height: '3px',
          zIndex: 9999
        }}
        showFastActions
      />
      <h1>Advanced Loading System</h1>
      <div style={{ display: 'flex', flexDirection: 'column', gap: '10px', maxWidth: '400px' }}>
        <button
          onClick={handleSingleRequest}
          style={{
            padding: '10px 20px',
            backgroundColor: '#007bff',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Single Request
        </button>
        <button
          onClick={handleMultipleRequests}
          style={{
            padding: '10px 20px',
            backgroundColor: '#28a745',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Multiple Requests
        </button>
        <button
          onClick={handleSequentialRequests}
          style={{
            padding: '10px 20px',
            backgroundColor: '#ffc107',
            color: 'black',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Sequential Requests
        </button>
      </div>
      {data && (
        <div style={{
          marginTop: '20px',
          padding: '15px',
          backgroundColor: '#d4edda',
          color: '#155724',
          borderRadius: '4px'
        }}>
          {data}
        </div>
      )}
      {error && (
        <div style={{
          marginTop: '20px',
          padding: '15px',
          backgroundColor: '#f8d7da',
          color: '#721c24',
          borderRadius: '4px'
        }}>
          Error: {error}
        </div>
      )}
    </div>
  );
}

export default AdvancedLoadingSystem;
Enter fullscreen mode Exit fullscreen mode

Create a custom hook for loading management:

// src/hooks/useLoadingBar.js
import { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { showLoading, hideLoading } from 'react-redux-loading-bar';

export const useLoadingBar = () => {
  const dispatch = useDispatch();

  const withLoading = useCallback(async (asyncFn) => {
    dispatch(showLoading());
    try {
      const result = await asyncFn();
      return result;
    } finally {
      dispatch(hideLoading());
    }
  }, [dispatch]);

  const startLoading = useCallback(() => {
    dispatch(showLoading());
  }, [dispatch]);

  const stopLoading = useCallback(() => {
    dispatch(hideLoading());
  }, [dispatch]);

  return {
    withLoading,
    startLoading,
    stopLoading
  };
};
Enter fullscreen mode Exit fullscreen mode

Update your store with proper configuration:

// src/store/index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { loadingBarReducer } from 'react-redux-loading-bar';
import thunk from 'redux-thunk';

const rootReducer = combineReducers({
  loadingBar: loadingBarReducer
});

export const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import AdvancedLoadingSystem from './AdvancedLoadingSystem';
import './App.css';

function App() {
  return (
    <div className="App">
      <AdvancedLoadingSystem />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This example demonstrates:

  • Redux-based loading bar
  • Single and multiple request handling
  • Sequential request management
  • Custom loading hook
  • Error handling with loading bar
  • Custom styling

Common Issues / Troubleshooting

  1. Loading bar not appearing: Ensure LoadingBar component is rendered in your app and loadingBarReducer is added to your Redux store. Also make sure you're dispatching showLoading actions.

  2. Redux store not configured: Make sure you've added the loadingBarReducer to your Redux store using combineReducers. The reducer must be named loadingBar.

  3. Actions not working: Ensure you're using useDispatch from react-redux to dispatch actions. Import showLoading and hideLoading from react-redux-loading-bar.

  4. Loading bar not hiding: Make sure you're calling hideLoading() in a finally block or after the async operation completes. If an error occurs, the loading bar should still be hidden.

  5. Multiple requests: react-redux-loading-bar handles multiple concurrent requests automatically. It shows the bar when any request starts and hides it when all requests complete.

  6. Styling issues: Use the style prop on the LoadingBar component to customize appearance. You can set backgroundColor, height, zIndex, and other CSS properties.

Next Steps

Now that you have an advanced understanding of react-redux-loading-bar:

  • Explore middleware integration for automatic loading
  • Learn about custom loading bar configurations
  • Implement loading bar with Redux Saga
  • Add loading bar to API interceptors
  • Integrate with React Router for route-based loading
  • Learn about other loading bar libraries
  • Check the official repository: https://github.com/mironov/react-redux-loading-bar
  • Look for part 52 of this series for more advanced topics

Summary

You've successfully integrated react-redux-loading-bar into your React application with Redux for advanced loading bar management. react-redux-loading-bar provides a Redux-based solution for displaying loading progress with automatic handling of multiple concurrent requests.

SEO Keywords

react-redux-loading-bar
React Redux loading bar
react-redux-loading-bar tutorial
React loading indicator
react-redux-loading-bar installation
React Redux loading
react-redux-loading-bar example
React progress bar
react-redux-loading-bar setup
React Redux middleware
react-redux-loading-bar customization
React loading state
react-redux-loading-bar actions
React Redux library
react-redux-loading-bar getting started

Top comments (0)