[Next.js] 페이지 로딩 처리하기 - app router

문지은·2024년 1월 5일
1

Next.js - App Router

목록 보기
4/20
post-thumbnail

Next.js 에서 웹 페이지가 데이터를 가져오거나 처리하는 동안 사용자에게 대기 상태를 시각적으로 보여주기 위해 로딩 UI 를 생성하는 두 가지 방법에 대해 알아보자.

<Suspense> 사용하기

  • 비동기적으로 데이터를 로드할 때 미리 정해진 컴포넌트를 렌더링하고, 로드가 완료되면 실제 데이터를 렌더링 하는 기능
  • React v18 부터는 Suspense 를 활용하여 컴포넌트가 렌더링 되는 동안 로딩 UI를 표시할 수 있다.
  • 코드를 간결하게 작성할 수 있고, 로딩 상태를 직접 관리할 필요가 없어진다.
  • 코드를 직접 작성해보면서, 동작 과정을 살펴보자.
    • react 에서 제공하는 Suspense 모듈을 가져와, 반환하려는 컴포넌트를 Suspense 태그로 감싸준다.
    • Suspense 태그에 fallback 속성을 적용해, 로딩 시 렌더링 될 UI를 작성한다.
    • 로딩 메세지는 메세지를 작성하거나, 아이콘 혹은 애니메이션 컴포넌트로 설정할 수 있다.

app/users/page.tsx

import React from "react";
import Link from "next/link";
import UserTable from "./UserTable";
import { Suspense } from "react";

interface Props {
  searchParams: { sortOrder: string };
}

const UsersPage = ({ searchParams: { sortOrder } }: Props) => {
  return (
    <div>
      <div>This is UserPage</div>
      <Link href="/users/new" className="btn btn-primary">
        New user
      </Link>
      <p>{new Date().toLocaleTimeString()}</p>
      <Suspense fallback={<p>Loading...</p>}>
        <UserTable sortOrder={sortOrder} />
      </Suspense>
    </div>
  );
};

export default UsersPage;
  • 이제 브라우저로 돌아가 페이지를 새로고침 하면, 로딩 메세지가 잠시 표시되는 것을 볼 수 있다.
  • 로딩 상태가 빠르게 변해서 잘 보이지 않을 때, 크롬 개발 도구에서 React Developer Tools 를 설치하면, Suspense 를 확인할 수 있다.

  • 개발자 도구 - Components 에서 Suspense 를 검색하면, Suspense 값을 확인할 수 있다.

  • Suspended : false 는 데이터가 잘 도착했으며, 최종 페이지가 렌더링 된 상태임을 의미한다.
  • 체크 박스를 클릭해 Suspensed : true 로 변경할 수 있으며, 변경하면 작성했던 로딩 UI 가 출력된다.

  • 다시 Suspended : false 로 바꾸고, 개발자 도구 - Network 탭으로 이동해 페이지 새로고침을 누르면, 서버에서 받은 문서를 확인할 수 있다.
    • 검색 엔진 봇이 보는 페이지는 빈페이지가 아닌 로딩 컴포넌트가 렌더링 된 문서이다.
    • 이는 검색 엔진 봇이 데이터를 볼 수 없어 데이터를 최적화에 영향을 미칠 것 같지만, 실제로는 그렇지 않다.
    • 서버는 사용자 페이지가 렌더링 될 때까지 대기하고, 추가 데이터를 클라이언트로 전달한다.
      • 이를 스트리밍이라 부른다.

특정 페이지에 여러 개의 서스펜스 컴포넌트를 가지고 있거나, 모든 페이지에 공통의 서스펜스 컴포넌트를 가지고 싶은 경우에는 어떻게 해야할까?

  • 공통 레이아웃에 자식 요소를 렌더링 하는 태그를 Suspense 컴포넌트로 감싸준다.
  • 자식 컴포넌트를 Suspense 컴포넌트로 감싸고 원하는 로딩 UI 를 fallback 속성으로 전달해주면 된다.
    • 이렇게 하면, 페이지 이동 시 로딩 메시지가 출력 되지만, 가벼운 앱에서는 매우 빠르게 지나가면서 보이지 않을 수도 있다.
    • 더 복잡한 앱에서는 페이지가 무겁게 로딩 될 때 로딩 메시지를 출력하며 사용자 경험을 향상시킬 수 있다.

app/layout.tsx

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import NavBar from "./NavBar";
import { Suspense } from "react";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" data-theme="winter">
      <body className={inter.className}>
        <NavBar />
        <main className="p-5">
          <Suspense fallback={<p>Loading...</p>}>{children}</Suspense>
        </main>
      </body>
    </html>
  );
}
  • 하지만, 위의 방법보다 더 직관적인 방법이 존재한다.
    • Next.js 에서 제공하는 loading.tsx 파일을 사용하는 것!

Next.js 의 loading.tsx 사용하기

loading.tsx

  • page.tsx, layout.tsx 와 같이 Next.js에서 약속한 파일명
  • 모든 컴포넌트에 공통으로 로딩 UI 를 적용하고 싶을 경우, layout 과 동일 하게 app 폴더 내에 loading.tsx 파일을 생성하고, 컴포넌트를 렌더링하면 된다.
  • 만약, 특정 라우터에 특정 로딩 UI 를 출력하고 싶은 경우에는 해당 라우터 폴더에 loading.tsx 파일을 생성하면, 해당 라우터에 대한 로딩 UI를 출력할 수 있다.
    • app/users/loading.tsx
    • app/admin/loading.tsx
    • app/products/loading.tsx
  • 공통 로딩 UI 를 만들어보자.

app/loading.tsx

import React from "react";

const Loading = () => {
  return <div>Loading..!</div>;
};

export default Loading;
  • 브라우저에서 확인해보면, 잘 적용된 것을 볼 수 있다.

profile
코드로 꿈을 펼치는 개발자의 이야기, 노력과 열정이 가득한 곳 🌈

0개의 댓글