I'm trying to add a pre-loader in my personal site, and the problem is that is cannot make it work. As you can see in image
I'm try to render it before router so that it runs before anything else.
code is simple
const [screenLoading, setScreenLoading] = useState(false);
useEffect(() => {
setScreenLoading(true);
setTimeout(() => {
setScreenLoading(false);
}, 1000);
}, []);
after a sec state will go false and site will load. but I am getting this error "Warning: Invalid hook call. Hooks can only be called inside of the body of a function component." which makes sense, but I don't have any return function to run the code inside.
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { useState, useEffect } from 'react';
//contexts
// import { MousePos } from './mousePosContext';
//components
import Header from './Header'
// import Footer from './Footer'
import ErrorPage from "./error-page";
//pages
import Home from './Home'
import Profile from "./Profile"
import Works from "./Works"
import Blogs from "./Blogs"
import Wm from "./works/web-monitization"
import Ss from "./works/scheduling-system"
import Bs from "./works/bharatSteel"
import Load from "./loader"
const [screenLoading, setScreenLoading] = useState(false);
useEffect(() => {
setScreenLoading(true);
setTimeout(() => {
setScreenLoading(false);
}, 1000);
}, []);
const router = createBrowserRouter([
{
path: "/",
element: <Header />,
errorElement: <ErrorPage />,
children: [
{
path: "",
element: <Home />,
index: true,
loader: async () => {
console.log("router loader called")
const test = (x) => {
console.log(x)
}
return test
}
},
{
path: "/profile",
element: <Profile />,
},
{
path: "/works",
element: <Works />,
},
{
path: "/works/web-monetization",
element: <Wm />
},
{
path: "works/input-validaton",
element: <Wm />
},
{
path: "works/scheduling-system",
element: <Ss proji="scheduling-system" />
},
{
path: "works/bharat-steel",
element: <Bs proji="scheduling-system" />
},
{
path: "blogs",
element: <Blogs />
},
{
path: "loader",
element: <Load />
}
]
}
]);
ReactDOM.createRoot(document.getElementById('root')).render(
<div className='layout'>
{screenLoading
? <Load />
: <RouterProvider router={router} />
}
</div>
)
So can someone tell me how to implement it, and if there is any other way to implement preloader with React-Router? The loader needs to run every time site loads for first time regard less of which page is being loaded.
The problem is unrelated to the react-router This line
const [screenLoading, setScreenLoading] = useState(false);
It's invalid, you can't use useState
outside of a component body. Same with useEffect
Create a component to fix that:
const Wrapper = () => {
const [screenLoading, setScreenLoading] = useState(false);
useEffect(() => {
setScreenLoading(true);
setTimeout(() => {
setScreenLoading(false);
}, 1000);
}, []);
return <div className='layout'>
{screenLoading? <Load /> :
<RouterProvider router={router} />}
</div>
}
ReactDOM.createRoot(document.getElementById('root')).render(<Wrapper />)