Next.js頁面之間跳轉新增loading bar功能

Awbeci發表於2021-12-25

前言

next.js框架是主流的SSR框架,強大的開箱即用加上社群非常活躍讓它能夠在眾多框架中脫穎而出。最近為了實現next.js頁面之間來回跳轉加上loading效果提升使用者體驗寫下這篇文章,希望能夠幫助到大家。

操作

首先,我們來分析一下實現原理,首先路由之間跳轉啟動與結束要有監聽事件,用到的就是next.js的router監聽事件
image.png

有了監聽事件我們就能夠很好的控制頁面之間的跳轉。

接著我們需要一個loading bar置頂到頁面最上面,這裡我們會用到@tanem/react-nprogress這個外掛

yarn add @tanem/react-nprogress

image.png

接著,我們開啟這個地址,複製裡面的程式碼到我們的專案中。

1、新建globalLoading.js

import React from 'react';
import { useNProgress } from '@tanem/react-nprogress';
const GlobalLoading = ({ isRouteChanging, }) => {
  const { animationDuration, isFinished, progress } = useNProgress({
    isAnimating: isRouteChanging,
  })

  return (
    <>
      <style jsx>{`
        .container {
          opacity: ${isFinished ? 0 : 1};
          pointerevents: none;
          transition: opacity ${animationDuration}ms linear;
        }
        .bar {
          background: #29d;
          height: 2px;
          left: 0;
          margin-left: ${(-1 + progress) * 100}%;
          position: fixed;
          top: 0;
          transition: margin-left ${animationDuration}ms linear;
          width: 100%;
          z-index: 1031;
        }
        .spinner {
          box-shadow: 0 0 10px #29d, 0 0 5px #29d;
          display: block;
          height: 100%;
          opacity: 1;
          position: absolute;
          right: 0;
          transform: rotate(3deg) translate(0px, -4px);
          width: 100px;
        }
      `}</style>
      <div className="container">
        <div className="bar">
          <div className="spinner" />
        </div>
      </div>
    </>
  )
};

export default GlobalLoading;

2、修改_app.js

const MyApp = ({Component, pageProps}) => {
  const router = useRouter()

  const [state, setState] = useState({
    isRouteChanging: false,
    loadingKey: 0,
  })

  useEffect(() => {
    const handleRouteChangeStart = () => {
      setState((prevState) => ({
        ...prevState,
        isRouteChanging: true,
        loadingKey: prevState.loadingKey ^ 1,
      }))
    }

    const handleRouteChangeEnd = () => {
      setState((prevState) => ({
        ...prevState,
        isRouteChanging: false,
      }))
    }

    router.events.on('routeChangeStart', handleRouteChangeStart)
    router.events.on('routeChangeComplete', handleRouteChangeEnd)
    router.events.on('routeChangeError', handleRouteChangeEnd)

    return () => {
      router.events.off('routeChangeStart', handleRouteChangeStart)
      router.events.off('routeChangeComplete', handleRouteChangeEnd)
      router.events.off('routeChangeError', handleRouteChangeEnd)
    }
  }, [router.events])

  return <>
    <GlobalLoading isRouteChanging={state.isRouteChanging} key={state.loadingKey} />
    <Component {...pageProps} />
  </>
}

export default wrapper.withRedux(MyApp)

這樣就完成了所有程式碼的編寫,接著,我們執行下專案,看看頁面之間來回切換是否擁有了loading bar的效果了。
image.png

Nice!

演示地址

總結

瞭解實現原理再加上社群牛人的貢獻,記住常去next.js官網看看最新的動向以及新版本新加了哪些功能,比如最近next.js 12新增了middleware功能等等。

引用

next.js loading bar視訊教程
next.js middleware

相關文章