본문 바로가기
개발일지/NextJS

NextJs에서의 로딩 처리

by 한삐 2022. 11. 29.
728x90

모든 페이지를 미리 렌더링하는 NextJS 특성상, 다른 페이지로 라우팅이 진행될때,

사용자는 가만히 멈춰있는 화면을 보게될 수 있다.

 

오늘은 nextJS에서의 로딩을 적용해줘봤다.

 

 

// _app.tsx

// 미리 만들어놓은 로딩 훅과 로딩 스피너
import { useLoading } from "src/hooks/useLoading"; 
import { LoadingSpinner } from "src/components/videos/video/LoadingSpinner"; 

<Layout>
    {isLoading ? <LoadingSpinner /> : null}
    <Component {...pageProps} />
</Layout>

 

로딩스피너는 CSS로 만들어도 좋고, SVG나 GIF, 라이브러리 등 자유롭게 적용하면 좋을 것 같다.

 

// useLoading.ts

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

export const useLoading = () => {
  const [nowLoading, setNowLoading] = useState<boolean>(false);
  useEffect(() => {
    const start = () => {
      setNowLoading(true);
    };
    const end = () => {
      setNowLoading(false);
    };
    Router.events.on("routeChangeStart", start);
    Router.events.on("routeChangeComplete", end);
    Router.events.on("routeChangeError", end);
    return () => {
      Router.events.off("routeChangeStart", start);
      Router.events.off("routeChangeComplete", end);
      Router.events.off("routeChangeError", end);
    };
  }, []);

  return nowLoading ? true : false;
};

 

라우팅 시 적용될 이벤트

 

routeChangeStart(url, { shallow }) - 라우트가 변경되기 시작할때 트리거됨.

routeChangeComplete(url, { shallow }) - 라우트가 완전히 변경되었을 때 트리거됨.

routeChangeError(err, url, { shallow }) - 라우트 변경 중에 에러가 발생했거나, 취소되었을 때 트리거됨.

 

_app.tsx(jsx)에 로딩 스피너나 로딩 페이지를 적용해 놓으면,

라우팅으로 인한 페이지 이동이 일어날 때마다 원하는 로딩 창을 호출해줄 수 있다.

 

- 적용된 페이지 -

 

 

 

아무쪼록 잘 적용된 것을 볼 수 있다. bb

 

 

 


로딩 스피너 소스코드

 

// LoadingSpinner.tsx

import styled from "styled-components";

export const LoadingSpinner = () => {
  return (
    <Spinner>
      <div className="spinner"></div>
    </Spinner>
  );
};

const Spinner = styled.div`
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  @keyframes spinner {
    from {
      transform: rotate(0deg);
    }
    50% {
      transform: rotate(180deg);
    }
    to {
      transform: rotate(360deg);
    }
  }

  & .spinner {
    box-sizing: border-box;
    position: absolute;
    top: 50%;
    left: 50%;
    width: 64px;
    height: 64px;
    margin-top: -32px;
    margin-left: -32px;
    border-radius: 50%;
    border: 6px solid transparent;
    border-top-color: #df9e75;
    border-bottom-color: #a9653b;
    animation: spinner 0.8s ease infinite;
  }
`;
728x90

댓글