페이지를 이동할 때 마다 Page Loader를 생성하고 싶었다.
그런데 매 페이지의 파일마다 일일이 Page Loader를 추가하는 건 비효율적이라고 생각했다.
아예 pages/_app.js
에서 처리할 수 있는 방법이 있을 거라 생각해서 공식문서를 읽었고, 역시 공식문서에 방법이 있었다.
Next.js Router에는 지원되는 여러 이벤트들이 있다.
그중에 내가 사용한 이벤트는 다음과 같다.
routeChangeStart(url, { shallow })
: 라우트가 바뀌기 시작할 때 작동한다.
routeChangeComplete(url, { shallow })
: 라우트가 다 바뀌었을 때 작동한다.
routeChangeError(err, url, { shallow })
: 라우트가 바뀌는 중 에러가 발생하거나 라우트를 불러오는 걸 취소할 때 작동한다.
ℹ️ 참고로 이 셋 모두 파라미터가 없어도 동작한다.
공식 문서에서 나온 예시 코드는 다음과 같다.
import { useEffect } from 'react'
import { useRouter } from 'next/router'
export default function MyApp({ Component, pageProps }) {
const router = useRouter()
useEffect(() => {
const handleRouteChange = (url, { shallow }) => {
console.log(
`App is changing to ${url} ${
shallow ? 'with' : 'without'
} shallow routing`
)
}
router.events.on('routeChangeStart', handleRouteChange)
// If the component is unmounted, unsubscribe
// from the event with the `off` method:
return () => {
router.events.off('routeChangeStart', handleRouteChange)
}
}, [router])
return <Component {...pageProps} />
}
useEffect
를 사용하여 router를 동작할 때마다 이벤트를 사용할 수 있는 걸 알 수 있다.
이를 기반으로 나는 다음과 같이 코드를 짰다.
pages/_app.js
전체 코드
import "@/styles/globals.css";
import Head from "next/head";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import LoadingSpinner from "@/components/parts/LoadingSpinner";
function App({ Component, pageProps }) {
const [isLoading, setIsLoading] = useState(false);
const router = useRouter();
useEffect(() => {
const handleRouteChange = () => setIsLoading(true);
const handleRouteComplete = () => setIsLoading(false);
const handleRouteChangeError = (err, url) => {
if (err.cancelled) {
console.log(`Route to ${url} was cancelled!`);
}
setIsLoading(false);
};
router.events.on("routeChangeStart", handleRouteChange);
router.events.on("routeChangeComplete", handleRouteComplete);
router.events.on("routeChangeError", handleRouteChangeError);
return () => {
router.events.off("routeChangeStart", handleRouteChange);
router.events.off("routeChangeComplete", handleRouteComplete);
router.events.off("routeChangeError", handleRouteChangeError);
};
}, [router]);
return (
<>
<Head>
{/* 생략 */}
</Head>
{isLoading ? (
<div>
<LoadingSpinner />
</div>
) : (
<Component {...pageProps} />
)}
</>
);
}
export default App;
감사합니다. 이런 정보를 나눠주셔서 좋아요.