Next.js 13의 앱 라우터는 페이지, 공유 레이아웃, 템플릿을 쉽게 생성할 수 있는 파일 컨벤션들을 제공합니다. 이 페이지에서는 이러한 특별한 파일들을 Next.js 애플리케이션에서 어떻게 사용할 수 있는지 알아볼 겁니다.
하나의 페이지는 하나의 루트에 단일한 UI를 나타냅니다. page.js
파일에 컴포넌트를 익스포트함으로써 페이지들을 정의할 수 있습니다. 루트를 정의하기 위해 중첩된 폴더들을 사용하고, 루트에 공개적으로 접근 가능하도록 하기 위해 page.js
파일을 사용합니다.
app
디렉토리 내에 page.js
를 추가해서 첫번 째 페이지를 생성해 보세요.
// app/page.js
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
알아두면 좋은 것:
.js
, .jsx
, 또는 .tsx
파일 확장자 또한 페이지에 사용될 수 있습니다.page.js
는 루트 세그먼트를 공개적으로 접근 가능하도록 하기 위해 필요합니다.레이아웃은 여러 페이지들이 공유하는 UI 입니다. 네비게이션에서, 레이아웃은 상태를 보존하고, 인터랙티브한 상태를 유지하며, 리렌더링 하지 않습니다. 레이아웃 또한 중첩할 수 있습니다.
layout.js
파일에 리액트 컴포넌트를 default
로 익스포트해서 레이아웃을 정의할 수 있습니다. 해당 컴포넌트는 반드시 children
prop을 받아야 하며, 이는 렌더링 하는 동안 자식 페이지나 자식 레이아웃 (존재하는 경우)을 뽑아낼 겁니다.
// app/dashboard/layout.tsx
export default function DashboardLayout({
children, // will be a page or nested layout
}: {
children: React.ReactNode,
}) {
return (
<section>
{/* Include shared UI here e.g. a header or sidebar */}
<nav></nav>
{children}
</section>
);
}
알아두면 좋은 것:
html
과 body
태그를 꼭 포함해야 합니다.children
prop을 이용하여 아래에 있는 자식 레이아웃들을 감싸게 됩니다..js
, .jsx
, 또는 .tsx
파일 확장자 또한 레이아웃에 사용될 수 있습니다.layout.js
와 page.js
파일은 같은 폴더 안에 정의될 수 있습니다. 레이아웃은 페이지를 감싸게 될 겁니다.루트 레이아웃은 app
디렉토리의 가장 상단에 정의되며, 모든 루트에 적용됩니다. 이 레이아웃은 서버로부터 리턴된 초기의 HTML을 수정할 수 있도록 도와 줍니다.
//app/layout.tsx
export default function RootLayout({ children }: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
알아두면 좋은 것:
app
디렉토리는 반드시 루트 레이아웃을 포함해야 합니다.<html>
과 <body>
태그를 반드시 정의해야 합니다.<head>
HTML 요소들을 관리하기 위해 빌트인 SEO 서포트를 사용할 수 있습니다. 예를 들어 <title>
요소와 같이요.하나의 폴더 안에 정의된 레이아웃은 (예를 들면 app/dashboard/layout.js
) 특정한 루트 세그먼트 (예를 들면 acme.com/dashboard
) 에 적용되며, 이 세그먼트가 활성된 상태일 때 렌더됩니다. 기본적으로, 파일 위계 안의 레이아웃들은 중첩되어 있으며, 이는 children
prop 을 통해 자식 레이아웃들을 감싼다는 의미입니다.
// app/dashboard/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode,
}) {
return <section>{children}</section>;
}
만약 위 예시의 두 레이아웃을 합치려고 한다면, 루트 레이아웃 (app/layout.js
) 가 app/dashboard/*
안의 루트 세그먼트를 감싸는 dashboard 레이아웃 (app/dashboard/layout.js
)를 감쌀 겁니다.
두 개의 레이아웃은 아래와 같이 중첩됩니다:
공유 레이아웃 안팎으로 특정 루트 세그먼트를 도입하기 위해서는 루트 그룹을 사용할 수 있습니다.
템플릿은 각각의 자식 레이아웃이나 페이지를 감싼다는 점에서 레이아웃과 비슷합니다. 루트를 가로질러 보존되고 상태를 유지하는 레이아웃과 다르게, 템플릿은 네비게이션 상의 각각의 자식을 위해 새로운 인스턴스를 생성합니다. 이는 유저가 하나의 템플릿을 공유하는 루트 사이사이를 탐방할 때, 컴포넌트의 새로운 인스턴스들이 마운트되고, DOM 요소들이 재생성되고, 상태가 보존되지 않으며, 이펙트들이 다시 조율된다는 의미입니다.
이러한 특정 행동들을 필요로 할 때가 있을 겁니다. 그리고 템플릿은 레이아웃보다 더 좋은 옵션이 될 수 있습니다. 예를 들어:
useEffect
에 의존하는 기능들 (예를 들어 페이지 뷰를 기록) 또는 useState
(페이지 기반의 피드백 양식)추천: 템플릿을 사용해야 할 특별한 이유가 없는 경우 레이아웃을 사용하는 것을 추천해요.
템플릿은 template.js
파일 안에 디폴트 리액트 컴포넌트를 익스포트 해서 정의할 수 있습니다. 이 컴포넌트는 children
prop을 받게 되며, 이는 중첩 세그먼트가 됩니다.
// app/template.tsx
export default function Template({ children }: {
children: React.ReactNode
)} {
return <div>{children}</div>
}
레이아웃이나 템플릿과 함께 루트 세그먼트의 렌더된 결과물은 아래와 같을 겁니다:
// Output
<Layout>
{/* 템플릿은 고유한 키를 갖는다는 점을 기억하세요 */}
<Template key={routeParam}>{children}</Template>
</Layout>
<head>
(<head
태그 수정하기)app
디렉토리 안에서, 빌트인 SEO 서포트를 통해 <title>
이나 <meta>
와 같은 <head>
HTML 요소들을 수정할 수 있습니다.
메타데이터들은 layout.js
나 page.js
파일 안에서 metadata
객체를 익스포트하거나, generateMetadata 함수
를 통해 정의될 수 있습니다.
// app/page.tsx
export const metadata = {
title: 'Next.js'
};
export default function Page() {
return '...'
}
알아두면 좋은 것: 수동으로
<title>
이나<meta>
와 같은<head>
태그를 루트 레이아웃에 적용하면 안 됩니다. 대신에, 반드시 자동으로 향상된 피필요 조건들을 핸들링하는 메타데이터 API를 사용해야 합니다. (예를 들어 스트리밍이나<head>
태그 중복을 제거하는 등)