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.js
at first but in the middle change toLoaderProvider.tsx
Hey @denusklo,
Thank you for the suggestion!
I think there's a typo; I'll correct it.