Skip to content

Instantly share code, notes, and snippets.

@agilworld
Created July 16, 2025 09:19
Show Gist options
  • Save agilworld/5d74022f76d5d8be1a2d224aa12a59aa to your computer and use it in GitHub Desktop.
Save agilworld/5d74022f76d5d8be1a2d224aa12a59aa to your computer and use it in GitHub Desktop.
Create Loading UI Middleware with React Context & Redux JS toolkit
import { useState, useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { LoadingProvider, useLoading, setLoadingFunction } from './contexts/LoadingContext';
function App() {
return (
<LoadingProvider>
<LoadingFunctionSetter />
<MainContent />
</LoadingProvider>
);
}
function LoadingFunctionSetter() {
const { setIsLoading } = useLoading();
useEffect(() => {
setLoadingFunction(setIsLoading);
}, [setIsLoading]);
return null;
}
function MainContent() {
const { isLoading } = useLoading();
return (
<>
{isLoading && <LinearProgress sx={{zIndex:1500}} color="warning" />}
<Router>
<Routes>
<Route path="/login" element={<Login />} />
{/* Redirect root to dashboard or login */}
<Route path="/" element={<Navigate to="/dashboard" replace />} />
{/* Protected dashboard routes */}
<Route
path="/dashboard"
element={
<ProtectedRoute requireRole={['superadmin', 'manager']}>
<Dashboard />
</ProtectedRoute>
}
/>
{/* Catch-all route for 404 */}
<Route path="*" element={<Navigate to="/dashboard" replace />} />
</Routes>
</Router>
</>
);
}
export default App;
import React, { createContext, useState, useContext } from 'react';
interface LoadingContextType {
isLoading: boolean;
setIsLoading: (isLoading: boolean) => void;
}
const LoadingContext = createContext<LoadingContextType | undefined>(undefined);
export const LoadingProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [isLoading, setIsLoading] = useState(false);
return (
<LoadingContext.Provider value={{ isLoading, setIsLoading }}>
{children}
</LoadingContext.Provider>
);
};
export const useLoading = () => {
const context = useContext(LoadingContext);
if (context === undefined) {
throw new Error('useLoading must be used within a LoadingProvider');
}
return context;
};
// Create a ref to store the setIsLoading function
let setLoadingRef: ((isLoading: boolean) => void) | null = null;
// Function to set the ref
export const setLoadingFunction = (func: (isLoading: boolean) => void) => {
setLoadingRef = func;
};
// Function to be used in middleware
export const setLoadingState = (isLoading: boolean) => {
if (setLoadingRef) {
setLoadingRef(isLoading);
}
};
import { Middleware } from '@reduxjs/toolkit';
import { setLoadingState } from '../contexts/LoadingContext';
const loadingMiddleware: Middleware = () => (next) => (action:any) => {
if (action.type.endsWith('/pending')) {
setLoadingState(true);
} else if (action.type.endsWith('/fulfilled') || action.type.endsWith('/rejected')) {
setLoadingState(false);
}
return next(action);
};
export default loadingMiddleware;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment