Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading Screen on next js page transition

I am trying to implement a loading screen when changing routes in my Nextjs app ,for example /home -> /about.

My current implementation is as follows. I am setting the initial loaded state to false and then changing it on componentDidMount. I am also calling the Router.events.on function inside componentDidMount to change the loading state when the route change starts.

_app.js in pages folder

class MyApp extends App {
  constructor(props) {
    super(props);
    this.state = {
      loaded: false,
    };
  }

  componentDidMount() {
    this.setState({ loaded: true });
    Router.events.on('routeChangeStart', () => this.setState({ loaded: false }));
    Router.events.on('routeChangeComplete', () => this.setState({ loaded: true }));
  }



  render() {
    const { Component, pageProps } = this.props;

    const { loaded } = this.state;

    const visibleStyle = {
      display: '',
      transition: 'display 3s',
    };
    const inVisibleStyle = {
      display: 'none',
      transition: 'display 3s',
    };
    return (
      <Container>
        <>
          <span style={loaded ? inVisibleStyle : visibleStyle}>
            <Loader />
          </span>
          <span style={loaded ? visibleStyle : inVisibleStyle}>
            <Component {...pageProps} />
          </span>
        </>
      </Container>
    );
  }
}

This works perfectly fine but I feel like there may be a better solution more elegant solution. Is this the only way which isn't cumbersome to implement this loading feature or is there an alternative ?

like image 398
Muljayan Avatar asked Apr 11 '19 04:04

Muljayan


People also ask

How do you make a preloader on NextJS?

Let us start by installing the dependencies that we need in this project. We'd start by creating a nextjs app. The command below gets the dependencies that we need in a Nextjs app. We'll make use of the "styled-component" library to style the loading screen component.

Can you use framer motion with next js?

Once you have Next. js set up, install Framer Motion as a dependency of your project. To start, we need to make some changes to the page and component hierarchy so that the animation we create only runs when a route change happens.


2 Answers

Why not use nprogress as follows in _app.js

import React from 'react';
import Router from 'next/router';
import App, { Container } from 'next/app';
import NProgress from 'nprogress';

NProgress.configure({ showSpinner: publicRuntimeConfig.NProgressShowSpinner });

Router.onRouteChangeStart = () => {
  // console.log('onRouteChangeStart triggered');
  NProgress.start();
};

Router.onRouteChangeComplete = () => {
  // console.log('onRouteChangeComplete triggered');
  NProgress.done();
};

Router.onRouteChangeError = () => {
  // console.log('onRouteChangeError triggered');
  NProgress.done();
};

export default class MyApp extends App { ... }

Link to nprogress.

You also need to include style file as well. If you put the css file in static directory, then you can access the style as follows:

<link rel="stylesheet" type="text/css" href="/static/css/nprogress.css" />

Make sure the CSS is available in all pages...

It will work for all your routes changing.

like image 156
MoHo Avatar answered Oct 11 '22 14:10

MoHo


Using the new hook api, this is how I would do it..

function Loading() {
    const router = useRouter();

    const [loading, setLoading] = useState(false);

    useEffect(() => {
        const handleStart = (url) => (url !== router.asPath) && setLoading(true);
        const handleComplete = (url) => (url === router.asPath) && setLoading(false);

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

        return () => {
            router.events.off('routeChangeStart', handleStart)
            router.events.off('routeChangeComplete', handleComplete)
            router.events.off('routeChangeError', handleComplete)
        }
    })
    
    return loading && (<div>Loading....{/*I have an animation here*/}</div>);
}

Now <Loading/> is going to show up whenever the route will change... I animate this using react-spring, but you can use any library you prefer to do this.

You can even take a step further and modify when the component shows up by modifying the handleStart and handleComplete methods that gets a url.

like image 44
Rohit Krishnan Avatar answered Oct 11 '22 13:10

Rohit Krishnan