Web applications frequently include loading indicators, which give users indicators of progress while information or data is being retrieved or processed. In this article, we'll use React's Context API to develop a reusable loader component.
Setting Up the Project
First, let's set up a new React project. Make sure you have Node.js and npm installed, and then run the following commands:
npm init @vitejs/app loader-provider-demo --template react
cd loader-provider-demo
Creating the Loader Context
Create a new file named LoaderContext.tsx in the src folder. This file will define our loader context and provide the necessary context provider and consumer components.
import React, { ReactNode, createContext, useState } from 'react';
import { Loader } from '../component/Loader';
type LoaderContext = {
showLoader: (message: string) => void;
hideLoader: () => void;
};
type LoaderContextProvider = {
children: ReactNode;
};
export const LoaderContext = createContext<LoaderContext | undefined>(
undefined
);
export const LoaderProvider: React.FC<LoaderContextProvider> = ({
children,
}) => {
const [isVisible, setIsVisible] = useState<boolean>(false);
const [loaderMessage, setLoaderMessage] = useState<string | undefined>();
const contextValue: LoaderContext = {
showLoader: (message) => {
setLoaderMessage(message);
setIsVisible(true);
},
hideLoader: () => {
setIsVisible(false);
},
};
return (
<LoaderContext.Provider value={contextValue}>
{isVisible && <Loader message={loaderMessage} />}
{children}
</LoaderContext.Provider>
);
};
Create a new file named useLoader.ts in the src/hooks folder.
import { useContext } from "react";
import { LoaderContext } from "../context/LoaderProvider";
export const useLoader = ()=>{
const context = useContext(LoaderContext);
if (!context) {
throw new Error("useLoader must be used within a LoaderProvider");
}
return context;
}
Creating the Loader Component
Next, let's create the Loader component ( create Loader.tsx file in src/components/loader folder) that will display the loading indicator:
import React from 'react';
import "./Loader.css";
type Loader = {
message: string | undefined;
};
export const Loader: React.FC<Loader> = ({ message }) => {
return (
<div className="loader">
<span className="spinner"></span>
<span className="loader-message">{message}</span>
</div>
);
};
Styling the Loader Component
Add the following CSS code to a file named Loader.css in your src/components/loader folder to style the loader component:
.loader{
position: absolute;
z-index: 99999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100vw;
height: 100vh;
background-color: white;
opacity: 0.9;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.spinner{
width: 60px;
height: 60px;
border: 10px solid #ccc;
border-top: 10px solid #2F73A3;
border-radius: 50%;
animation: spin 1.5s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loader-message{
margin-top: 10px;
font-size: 22px;
font-weight: 600;
color : #2F73A3;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
Using the Loader Context
Now, let’s use our LoaderProvider in the main.tsx file:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { LoaderProvider } from './context/LoaderProvider.tsx';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<LoaderProvider>
<App />
</LoaderProvider>
</React.StrictMode>
);
Using the Custom Hook to Show Loader
In any component where you want to show the loader, you can use the useLoader custom hook:
import './App.css';
import { useLoader } from './hooks/useLoader';
function App() {
const { showLoader, hideLoader } = useLoader();
return (
<>
<button onClick={() => showLoader("Please wait!")}>Show Loader</button>
<button style={{position:'absolute',zIndex:"99999"}} onClick={() => hideLoader()}>hide Loader</button>
</>
);
}
export default App;
Conclusion
In this tutorial, we've created a loader component using React's Context API, allowing us to manage loading states globally across our application. This approach provides a clean and efficient way to handle loading indicators and can be easily extended to suit different use cases.
Feel free to customize the loader component's appearance and behavior to fit your application's needs.
Happy coding!
Top comments (2)
got a few typos. use
LoaderContext.jsat first but in the middle change toLoaderProvider.tsxHey @denusklo,
Thank you for the suggestion!
I think there's a typo; I'll correct it.