Dog foot print

app router의 기본 파일들 (page, layout, template) 본문

Next.js/파일

app router의 기본 파일들 (page, layout, template)

개 발자국 2023. 11. 27. 14:42

 

기존 pages와 달리 app은 매우 복잡한 폴더 구조와 파일구조를 가지고 있다. 이는 폴더구조를 이용하여, 다양한 기능들을 제공하려는 노력으로 보이는데, 개인적으로 “폴더구조가 너무 깊어 복잡하고 쓰임이 정해진 파일들을 얼마나 잘 활용 할 수 있을까?” 라는 생각이 든다.

Page file

이제 더 이상 파일명을 기준으로 하위 경로를 생성하지 않는다. 하위 경로는 폴더명을 기준으로 생성된다. 이렇게 생성된 page 파일들은 자신이 속한 폴더의 인덱스 경로로 지정된다. 예를 들어 /about/page.tsx 파일은 /about 과 일치하며, /about/more/page.tsx 파일은 /about/more 경로와 일치하게 된다.

Props

interface Params{
    [key in string] : string | string[]
}

interface PageProps{
    params? : Params,
    searchParams? : Params
}

 

 

Example URL params
app/shop/[slug]/page.js /shop/1 { slug: '1' }
app/shop/[category]/[item]/page.js /shop/1/2 { category: '1', item: '2' }
app/shop/[...slug]/page.js /shop/1/2 { slug: ['1', '2'] }

 

No more getServerSideProps & getStaticProps

import { getTodos } from "@/api/fake";
import styles from "./page.module.css";

// app/page.tsx
export default async function Home() {
  const todos = await getTodos();

  return (
    <main className={styles.main}>
      {todos.map((v) => (
        <div key={v.id}>{v.title}</div>
      ))}
    </main>
  );
}

 

 

이전과 달리 경로의 엔드포인트를 담당하는 page.tsx에서는 더 이상 getServerSidePropsgetStaticProps, getStaticPaths가 사용되지 않는다. 이는 page.tsx에서 기본으로 내보낸 컴포넌트가 server-component 이며, 컴포넌트 내부에서 데이터를 패칭하고 캐싱하는 형태로 getServerSidePropsgetStaticProps 를 대체하였다.

Tip : 서버 컴포넌트와 데이터 캐싱과 관련하여 자세한 내용은 아래의 링크를 참조하면 된다.

 

Building Your Application: Caching
https://nextjs.org/docs/app/building-your-application/rendering/server-components

Layout file

Layout 파일은 요청을 받은 페이지까지의 레이아웃을 정의한다. 해당 페이지로 향하는 경로중에 layout 컴포넌트가 존재하면, 페이지가 레이아웃에 의해 중첩되어 레이아웃을 구성한다. 이 layout파일도 page파일과 동일하게 server-component 로써 이곳에서 데이터를 패칭 할 수 있다.

 

No more _app.tsx && _document.tsx

이전 pages 폴더에서 app.tsx_document.tsx 파일은 각각 다음과 같은 역할을 하였는데, 삭제되었고 아래의 역할은 이제 app 경로내 최상단 layout 파일에서 이루어져야 한다.

 

  • _app.tsx : 가장 먼저 실행되는 컴포넌트로써, 모든 페이지에 공통으로 Provider들로 감싸거나 레이아웃을 적용할 때 사용.
  • _document.tsx : 공통으로 적용되는 html , head, body를 컨트롤 하는 역할로 사용된다.

 

_app.tsx와 _document와 다른 변경사항으로는 다음과 같다.

  • hook과 react와 관련된 내용을 직접 호출 할 수 없다.
    • 클라이언트 컴포넌트를 호출 하는 것으로 이를 대체한다.
  • metaData와 관련된 값들은 중첩된 곳에서 정의한 것으로 대체 될 수 있다.
  • next/document에서 Head,Body,Html을 호출하지 않아도 된다.
  • pageProps를 프롭스로 취급하지 않는다.
import "./globals.css";
import Providers from "@/Providers";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <title>헬로월드</title>
      </head>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

 

html을 구성하던 _document파일이 삭제되었으니 이를 app폴더 최상위 layout파일은 필수이다.

 

Props

 

Tip : params의 경우 호출되는 동일한 경로의 page와 같은 파라메터가 전달된다. 만약 중첩구조인 layout이 위치한 폴더의 path paramter가 존재하지 않는 경우 빈 객체인 params를 받는다.

 

interface LayoutProps{
    children : ReactNode,
    params? : Params
}

 

Example URL params
app/shop/[slug]/page.js /shop/1 { slug: '1' }
app/shop/[category]/[item]/page.js /shop/1/2 { category: '1', item: '2' }
app/shop/[...slug]/page.js /shop/1/2 { slug: ['1', '2'] }

Layout files do not received Props

 

page파일과 다르게 Layout파일은 searchParams를 프롭스로 받지 않는다. 그 이유는 페이지 파일간 공유되는 레이아웃은 경로에 의해 사용될 레이아웃 파일이 결정되고 searchParam의 변경시 동일한 하위 path를 가지는데 불필요하게 재 렌더링할 이유가 없기 때문이다.

 

searchParam이 필요하고 변경시 사용해야한다면 layout파일에 useSearchParam을 사용하는 클라이언트 컴포넌트를 사용하도록 하자.

Template File

이 파일은 하위 경로에 사용되는 page 파일을 감싸는 형태라는 점과 server-component라는 점에서 layout과 매우 유사하다.

//app/more/template.tsx
import { ReactNode } from "react";

export default function Template({ children }: { children: ReactNode }) {
  return <div>{children}</div>;
}
//app/more/layout.tsx
export default function Layout({ children }: { children: ReactNode }) {
  return <div>{children}</div>;
}

 

layout파일과 매우 유사하지만 특이점이 있는데, 이 파일은 아래의 코드처럼 routeParam이 key가 되어 작동한다는 것이다. 즉 routeParam이 변경될때마다 새롭게 컴포넌트를 생성한다.

<Layout>
  {/* Note that the template is given a unique key. */}
  <Template key={routeParam}>{children}</Template>
</Layout>

Layout과 Template 컴포넌트 초기화 조건

Layout : 변경된 URL경로에서 layout파일이 위치한 경로까지 pathParam의 변경이 존재하는 경우.
Template : 변경된 URL경로에서 pathParam이 변경되거나 사용하는 페이지파일이 변경되는 경우.

 

/more/1 -> /more/2 로 URL이동시

layout file 컴포넌트 초기화
/app/more/layout.js X
/app/more//layout.js O
/app/more//detail/layout.js X
/app/more/template.js O
/app/more//template.js O
/app/more//detail/template.js X

 

 

/more/1 -> /more/1/detail 로 URL이동시

layout file 컴포넌트 초기화
/app/more/layout.js X
/app/more//layout.js X
/app/more//detail/layout.js O
/app/more/template.js X
/app/more//template.js O
/app/more//detail/template.js O

 

/more/1/detail -> /more/1/comment 로 URL이동시

layout file 컴포넌트 초기화
/app/more/layout.js X
/app/more//layout.js X
/app/more//comment/layout.js O
/app/more/template.js O
/app/more//template.js O
/app/more//comment/template.js O

 

이처럼 레이아웃은 사용하는 pathParam만 같다면 새롭게 컴포넌트를 생성하지 않는데 반해 template파일은 사용하는 페이지가 변경될때마다 컴포넌트를 새롭게 생성한다. 이를 이용해, 페이지가 변경될때 마다 새롭게 상태와 사이드 이펙트를 발생시켜야하는 기능에 유리하다.

 

권장 사용 예시 :

  • 기능이 useState나 useEffect의 사용과 연관되는 경우.
    • ex : 페이지 별로 로깅을 하는 경우. (아날리틱스가 이를 대체가능함)
    • ex : 페이지당 피드백을 줄 수 있는 양식
  • 기존 프레임워크 기능을 변경하려는 경우
    • layout은 페이지를 요청할때, 한번만 loading 상태를 보여주고 변경시에는 보여주지 않지만 template는 페이지가 변경될때 마다 loading 상태를 보여줄 수 있다.

페이지가 변경될때마다 상태가 초기화되어야 하는 공통의 UI.

Props

Tip : params의 경우 호출되는 동일한 경로의 page와 같은 파라메터가 전달된다. 만약 중첩구조인 layout이 위치한 폴더의 path paramter가 존재하지 않는 경우 빈 객체인 params를 받는다.

interface TemplateProps{
    children : ReactNode,
}
반응형
Comments