7

How can I show my own loader instead of a blank white screen? For Example, Tweeter Shows the logo while the page is loading, same for Facebook, google AdSense, etc. Look at this Gif, I want something like this in Next Js.enter image description here

I guess this is something to do with the _document.js. There is a similar question for react js (render the loader in index.html) But I cant figure out how to do it in next js.

Sumit Dey
  • 119
  • 1
  • 1
  • 6
  • That's probably not use next.js, but an SPA. Besides that, why not set a background image? – evolutionxbox Jun 24 '21 at 15:17
  • 1
    The DOM rendering isn't usually what you're waiting on in these situation. It's pretty fast. What's usually slowing things down is actually fetching the JS itself or fetching data from your server to fill in the UI. – Brian Thompson Jun 24 '21 at 15:40
  • @evolutionxbox can you please explain the solution using background image? – Sumit Dey Jun 25 '21 at 06:05
  • @BrianThompson Would you happen to know if there's a way to lazy load everything except the loader, and then track that somehow to switch to main content once it loads? – MrTanguero Feb 23 '22 at 07:07

8 Answers8

9

To add splash screen on Nextjs, you can do it my several ways. Here is my prefered solution.

/**
 * inside _app.js function for remove the loader
 */
useEffect(() => {
  if (typeof window !== 'undefined') {
    const loader = document.getElementById('globalLoader');
    if (loader)
      loader.remove();
  }
}, []);
/* Style.css or global.css */

#globalLoader {
  position: fixed;
  z-index: 9999;
  top: 50%;
  left: 50%;
  background-color: #fff;
  transform: translate(-50%, -50%);
  width: 100%;
  height: 100%;
  justify-content: center;
  align-items: center;
  display: flex;
}
/** * on _document.js insert below code after body tag * More about _document.js -> https://nextjs.org/docs/advanced-features/custom-document */

<div id="globalLoader">
  <img src="https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif" alt="" />
</div>
Shiva Aryal
  • 141
  • 1
  • 7
4

Usually these are done by having a div that overlays everything and is shown by default, what you put in that div is up to you (gif, svg, etc). Once window.onload is called just hide the div and it will show the fully rendered dom.

here's a basic example of this (I'm on mobile so excuse my formatting) CSS:

.loadingsScreen{
        position:absolute;
        left:0;
        top:0;
        width:100%;
        height:100%;
        background-color: #whatever-color;
        z-index: 10;  /*just make sure it's the highest on the page*/
}

JS:

window.onload = function(){
        $("#loadingScreen").fadeOut(); //just make it hide the overlaying div, I used jQuery in this example but there are many ways to do this
};
KCGD
  • 675
  • 6
  • 10
2

No need to install any library

import { useRouter } from "next/router";
import { useState, useEffect } from "react";

function MyApp() {
  const router = useRouter();
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    router.events.on("routeChangeError", (e) => setLoading(false));
    router.events.on("routeChangeStart", (e) => setLoading(false));
    router.events.on("routeChangeComplete", (e) => setLoading(true));

    return () => {
      router.events.off("routeChangeError", (e) => setLoading(false));
      router.events.off("routeChangeStart", (e) => setLoading(false));
      router.events.off("routeChangeComplete", (e) => setLoading(true));
    };
  }, [router.events]);

  return <>{loading ? "loading..." : <AppComponent />}</>;
}
Chukwuemeka Maduekwe
  • 6,687
  • 5
  • 44
  • 67
1

Use suspense, nextjs supports it but there are things worth considering before using it.

Assuming you're using NextJs 13 with app directory:

Create a file loading.js or anyname in app directory. This will be your layout to show while the DOM is rendering, design it however you want, put gif/svgs whatever is required.

loading.js

export default function Loading() {
    return (
        <div className="fixed inset-0 bg-blue-500 z-[10000] flex flex-1 items-center justify-center">
        Loading
        </div>
    );
}

then your layout file should look like this:

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <Suspense fallback={<Loading />}>{children}</Suspense>
      </body>
    </html>
  );
}

As long as your DOM is rendered its gone, you'll see its rendered like a flas on some and slow on others that depends on your page size. You can look up, delaying Suspense or adding lazy component if you need.

Tip: use Lottie Animations for making a loading or any smaller sized svg and rotate is using css animations to keep suspense content smaller.

0

Actually this isn't something Next.js provides "from the box", you must implement such things yourself, you can use some global state (redux/context) to determine if your app is loading something or not, and render loader basing on this state.

Nikita Mazur
  • 1,602
  • 1
  • 5
  • 14
  • This isnt an answer. Also misses the point, this is for a loading screen before react has loaded. – GifCo Mar 21 '23 at 20:05
0

Try this logic. Create a state variable and make use of NextJs Router events. Use the router events to control the state variables and finally use the state variables to control the rendering of the loading screen and the other DOM elements.

   function MyApp(){
     const [loading, setLoading] = React.useState<boolean>(false);

     Router.events.on('routeChangeStart', (url) => {
       setLoading(true);
      });

     Router.events.on('routeChangeComplete', (url) => {
       setLoading(false);
     });
    

    return(
      <>
        {loading ? (
            <PageLoader />
          ) : (
            <AppLayout>
              <Component {...pageProps} />
            </AppLayout>
          )}
    </>
  )
}
-1

you can not. What you see is custom splash screen that the twitch loader is showing you. What it does is splitting the loading process in two parts. The first one is standard- the browser requests and receives html and script files that you provided to render the page. You can not bypass this stage with a conventional web application, what you can do to improve user experience however, is to minimize that time. A nice example would be an index.html that contains inline css and javascript that animates the splash screen, and once loaded starts the actual application. In such way the real data exchange is done after the browser has rendered a page. This requires you to do a lot of work while planning the application, but with the modern frameworks and tools there are certainly shorter and dirtier paths to achieve it. If you have a SPA however, this is pretty much only way you can go.

As a side-note, if you want to speed up the loading of your site(which is why splash screens are needed anyway), just run some profiling, an check for optimizations. Server-side caching normally gives you the best ROI, but it won't help you with heavier loads(large images, or large amount of small images). Segmentation of the html is the second best option. Then you should look at imported libraries and stuff, those tend to add a bit. Finally there are options to compress data on the server to limit the data load.

tstoev
  • 1,415
  • 11
  • 12
-1

You can use router.event.

See this link:

https://github.com/vercel/next.js/blob/canary/examples/with-loading/pages/_app.js

useEffect(() => { const handleStart = (url) => { console.log(Loading: ${url}) NProgress.start() } const handleStop = () => { NProgress.done() }

router.events.on('routeChangeStart', handleStart)
router.events.on('routeChangeComplete', handleStop)
router.events.on('routeChangeError', handleStop)

return () => {
  router.events.off('routeChangeStart', handleStart)
  router.events.off('routeChangeComplete', handleStop)
  router.events.off('routeChangeError', handleStop)
}

}, [router]);

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129