Next.js Discord

Discord Forum

Spinner (Page loader)

Unanswered
! nolikas posted this in #help-forum
Open in Discord
I made this spinner in a file preload.tsx:
"use client";
import { useState, useEffect } from "react";
import { TbLoader2 } from "react-icons/tb";

export default function Preloader() {
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const Timer = setTimeout(() => {
      setLoading(false);
    }, 2000);

    return () => clearTimeout(Timer);
  }, []);

  return loading ? (
    <div className="h-screen flex items-center justify-center">
      <TbLoader2 className="h-8 w-8 animate-spin" />
    </div>
  ) : null;
}

Then in layout I just display it like this: <Preload />
How can I make it so when the loader is active, other content of the page is all hidden and after 2 seconds loader disappears and initial page's content is visible?

78 Replies

you can use css with tailwind to do that
write a javascript script that toggles the classes name it for example Loader.ts can remove the classes of your page by adding hidden
and after make it wait 2 secends and then remove the hidden
doing it
// loader.ts
import { useState, useEffect } from "react";

export function useLoader(duration = 2000): boolean {
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const timer = setTimeout(() => {
      setLoading(false);
    }, duration);

    return () => clearTimeout(timer);
  }, [duration]);

  return loading;
}
here you go
then when i add the visible part
// loader.ts
import { useState, useEffect } from "react";

export function useLoader(duration = 2000): boolean {
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const timer = setTimeout(() => {
      setLoading(false);
    }, duration);

    return () => clearTimeout(timer);
  }, [duration]);

  // Set the visibility of the page to false while loading
  useEffect(() => {
    if (loading) {
      document.body.style.visibility = "hidden";
    } else {
      document.body.style.visibility = "visible";
    }
  }, [loading]);

  return loading;
}
here
@! nolikas
and where does the spinner part go?
<div className="h-screen flex items-center justify-center">
  <TbLoader2 className="h-8 w-8 animate-spin" />
</div>
sorry but i meant that you reqiure this in your loading page and then the loader goes in the page
So I put loader component in layout.tsx?
the loader.ts is required and yes i think
and finally how do I use useLoader in te layout?
i dont know dont know layout.tsx much
it's like _app.tsx in React
i never use _app or layout
in nextjs?
yes im new
oh damn
do you use > v13 or < 13 version?
14.2.1
Okay, we should get back to the topic
ok let get back
// loader.ts
"use client";
import { useState, useEffect } from "react";

export function useLoader(duration = 2000): boolean {
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const timer = setTimeout(() => {
      setLoading(false);
    }, duration);

    return () => clearTimeout(timer);
  }, [duration]);

  // Set the visibility of the page to false while loading
  useEffect(() => {
    if (loading) {
      document.body.style.visibility = "hidden";
    } else {
      document.body.style.visibility = "visible";
    }
  }, [loading]);

  return loading;
}
This is the component I have rn
like this
// layout.tsx
import { useLoader } from "./loader";
import Preloader from "./preload";

export default function Layout() {
  const loading = useLoader(); // You can pass duration as an argument if needed

  return (
    <>
      <Preloader /> {/* Render your Preloader component */}
      {/* Other content of the page */}
      <div style={{ visibility: loading ? "hidden" : "visible" }}>
        {/* Your page content goes here */}
      </div>
    </>
  );
}
this is ur layout.tsx
i now understand
💻
...
          <Spinner />
          <div style={{ visibility: loading ? "hidden" : "visible" }}>
            <Navbar user={user} />
            <div className="mx-auto my-4 flex max-w-7xl flex-1 justify-center items-center">
              {children}
            </div>
          </div>
...
I did it like that
let me check
oh well
tho we got one problem
what
Error: Attempted to call useLoader() from the server but useLoader is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.
use "use client"
at top
and I can't set layout.tsx to be client component, because metadata is set there
oh
then use the spiiner in a client component like page.tsx
but my navbar is displayed in layout
I need everything to be hidden
move your nav if you need
you mean I could do new component ("layout") in page.tsx where I do all the spinner logic?
no put everything the header the loader in your page
but..
wj
what
then navbar is not visible in all pages
cuz layout is made for that
oh
a part of website that is visible in any page
even error 404 page
make a div in the layout that conanids the navbar and content
i gtg
:fine:
So I finally managed to solve it by converting layout.tsx to a client component by adding "use client"; and moving metadata to page.tsx (it's not global metadata, so I have to set it for each page manually).
Still would be interested to know if that's a good practice or not.
but
u can do this
1. center the spinner and design it
2. add z-index 99999
3. add opacity to background or solid color so it doesnt see properly
just that
@Schneider’s Smooth-fronted Caiman 1. center the spinner and design it
well, my page is higher than screen height so would there a scroll bar appear?
@! nolikas well, my page is higher than screen height so would there a scroll bar appear?
Schneider’s Smooth-fronted Caiman
overflow: none;
on body
What I actually mean you to do is @! nolikas v
the first example
it seems good to me however ik you are not using material ui, I'm just tellig how should u design it
Oh