Next.js 13 내부의 앱 라우터는 페이지(page), 공유 레이아웃(layout) 및 템플릿(template)을 쉽게 생성하기 위한 새로운 파일 규칙을 도입했습니다. 이 페이지는 Next.js 애플리케이션에서 이러한 특수 파일을 사용하는 방법을 안내합니다.
페이지(Pages)
페이지는 경로에 고유한 UI입니다. 페이지를 정의하기 위해 page.js 파일에서 컴포넌트를 내보내는 방식을 사용할 수 있습니다. 중첩된 폴더를 사용하여 경로를 정의하고, route와 page.js 파일을 사용하여 해당 경로에 대해 공개적으로 접근할 수 있도록 만들 수 있습니다.
Good to know:
- 페이지는 항상 route subtree의 leaf 입니다. 그래서 컴포넌트 계층을 보면 페이지 컴포넌트가 가장 안쪽에 있는 자식 노드에 위치해 있습니다.
- 페이지 파일로는 .js, .jsx, or .tsx확장자를 사용할 수 있습니다.
- reoute 세그먼트에 공개적으로 접근 하려면page.js 파일이 필요합니다.
- 페이지는 기본적으로 서버 컴포넌트 이지만 클라이언트 컴포넌트로 설정할 수 있습니다.
- 페이지에서 data fetch을 할 수 있습니다.
레이아웃(Layouts)
레이아웃은 여러 페이지 간에 공유되는 UI입니다. 탐색 시 레이아웃은 상태를 유지하고 대화형 상태를 유지하며 다시 렌더링하지 않습니다. 레이아웃은 중첩될 수도 있습니다.
레이아웃을 정의하기 위해 layout.js 파일에서 default 로 React 컴포넌트를 내보낼 수 있습니다. 이 컴포넌트는 렌더링 중에 자식 레이아웃(있는 경우) 또는 자식 페이지로 채워질 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>
);
}
Good to know:
- 가장 상위에 있는 레이아웃을 "루트 레이아웃"이라고 합니다. 이 필수 레이아웃은 애플리케이션의 모든 페이지에서 공유됩니다. 루트 레이아웃은 html과 body 태그를 포함해야 합니다.
- 어떤 라우트 세그먼트든지 선택적으로 자체 레이아웃을 정의할 수 있습니다. 이러한 레이아웃은 해당 세그먼트의 모든 페이지에서 공유됩니다.
- 라우트 내의 레이아웃은 기본적으로 중첩됩니다. 각 부모 레이아웃은 하위의 자식 레이아웃을 React의 children prop을 사용하여 감쌀 수 있습니다.
- 공유 레이아웃을 사용하거나 사용하지 않도록 특정 라우트 세그먼트를 선택하는 데에는 Route Groups를 사용할 수 있습니다.
- 레이아웃은 기본적으로 서버 컴포넌트이지만 클라이언트 컴포넌트로 설정할 수도 있습니다.
- 레이아웃은 데이터를 가져올 수 있습니다.
- 부모 레이아웃과 그 자식 간에 데이터를 전달하는 것은 불가능합니다. 그러나 동일한 데이터를 라우트에서 여러 번 가져올 수 있으며, React는 자동으로 중복 요청을 제거하므로 성능에 영향을 주지 않습니다.
- 레이아웃은 현재 라우트 세그먼트에 접근할 수 없습니다. 라우트 세그먼트에 접근하기 위해서는 클라이언트 컴포넌트에서 useSelectedLayoutSegment 또는 useSelectedLayoutSegments를 사용할 수 있습니다
- 동일한 폴더에 layout.js와 page.js 파일을 정의할 수 있습니다. 레이아웃은 페이지를 감쌉니다.
- 레이아웃에는 .js, .jsx 또는 .tsx 확장자를 사용할 수 있습니다.
Root Layout (필수)
루트 레이아웃은 앱 디렉토리의 최상위 수준에서 정의되며 모든 경로에 적용됩니다. 이 레이아웃을 사용하면 서버에서 반환된 초기 HTML을 수정할 수 있습니다.
Good to know:
- 앱 디렉토리는 루트 레이아웃을 포함해야 합니다.
- 루트 레이아웃은 Next.js가 자동으로 생성하지 않기 때문에 <html> 및 <body> 태그를 정의해야 합니다.
- 내장된 SEO 지원을 사용하여 <head> HTML 요소(예: <title> 요소)를 관리할 수 있습니다.
- route 그룹을 사용하여 여러 루트 레이아웃을 만들 수 있습니다.
- 루트 레이아웃은 기본적으로 서버 컴포넌트이며 클라이언트 컴포넌트로 설정할 수 없습니다.
Nesting Layouts (중첩 레이아웃)
폴더 내에 정의된 레이아웃(예: app/dashboard/layout.js)은 특정 경로 세그먼트(예: acme.com/dashboard)에 적용되고 해당 세그먼트가 활성화될 때 렌더링됩니다. 기본적으로 파일 계층 구조의 레이아웃은 중첩됩니다. 즉, child props 통해 자식 레이아웃을 래핑합니다.
위의 두 레이아웃을 결합하는 경우 루트 레이아웃(app/layout.js)은 대시보드 레이아웃(app/dashboard/layout.js)을 래핑하고 app/dashboard/* 내부의 경로 세그먼트(page.js)를 래핑합니다.
두개의 레이아웃은 그림과 같이 중첩됩니다.:
또한 Route그룹을 사용하여 공유 레이아웃 안팎으로 특정 경로 세그먼트를 옵트인할 수 있습니다.
Templates
템플릿은 레이아웃과 유사하게 각 자식 레이아웃이나 페이지를 감싸는 역할을 합니다. 그러나 레이아웃과는 다르게 템플릿은 탐색할 때마다 자식 요소마다 새로운 인스턴스를 생성합니다. 이는 사용자가 템플릿을 공유하는 라우트 간에 이동할 때 컴포넌트의 새로운 인스턴스가 마운트되고, DOM 요소가 다시 생성되며, 상태가 보존되지 않고 효과가 다시 동기화된다는 것을 의미합니다.
아래와 같이 일부 특정 동작이 필요한 경우에는 레이아웃보다 템플릿이 더 적합한 옵션이 될 수 있습니다.
- Enter/exit animations using CSS or animation libraries: 템플릿을 사용하여 CSS 또는 애니메이션 라이브러리를 활용한 입/출입 애니메이션을 구현할 수 있습니다. 예를 들어, 페이지 간 전환 시 페이드 인/아웃 효과나 슬라이드 애니메이션 등을 적용할 수 있습니다.
- Features that rely on useEffect and useState: useEffect나 useState에 의존하는 기능을 구현해야 하는 경우 템플릿을 사용할 수 있습니다. 예를 들어, 각 페이지의 조회 기록을 로깅하거나 페이지별 피드백 양식을 제공하는 등의 기능을 템플릿 내에서 관리할 수 있습니다.
- Changing the default framework behavior: 기본 프레임워크 동작을 변경해야 하는 경우에도 템플릿을 사용할 수 있습니다. 예를 들어, 레이아웃 내의 Suspense 경계는 처음 로드될 때만 대체 콘텐츠를 표시하고, 페이지를 전환할 때는 표시하지 않습니다. 그러나 템플릿을 사용하면 각 탐색마다 대체 콘텐츠가 표시되도록 설정할 수 있습니다. 이를 통해 특정 탐색에서 로딩 상태를 보여주거나 추가적인 로딩 처리를 할 수 있습니다.
💡권장 사항: 템플릿을 사용해야 하는 특별한 이유가 없다면 레이아웃을 사용하는 것이 좋습니다.
템플릿은 template.js 파일에서 기본 React 컴포넌트를 내보내서 정의할 수 있습니다. templage 컴포넌트는 중첩된 세그먼트가 될 children props를 내재해야 합니다.
/* app/template.tsx */
export default function Template({ children }: { children: React.ReactNode }) {
return <div>{children}</div>;
}
레이아웃과 템플릿이 있는 Route 세그먼트의 렌더링된 출력은 다음과 같습니다.
<Layout>
{/* Note that the template is given a unique key. */}
<Template key={routeParam}>{children}</Template>
</Layout>
Modifying <head>
앱 디렉토리에서 내장된 SEO 지원을 사용하여 제목 및 메타와 같은 <head> HTML 요소를 수정할 수 있습니다. 메타데이터는 layout.js 또는 page.js 파일에서 메타데이터 객체 또는 generateMetadata 함수를 내보내서 정의할 수 있습니다.
/* app/page.tsx */
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Next.js',
};
export default function Page() {
return '...';
}
💡 <title> 및 <meta>와 같은 <head> 태그를 루트 레이아웃에 수동으로 추가하면 안 됩니다.
대신 <head> 요소 스트리밍 및 중복 제거와 같은 고급 요구 사항을 자동으로 처리하는 메타데이터 API를 사용해야 합니다.
느낀점
1. Layouts과 Templates 파일의 개념을 명확하게 잡고 가야 될거 같습니다.
Layouts:
- Layouts는 페이지 레이아웃을 정의하기 위한 파일입니다.
- 일반적으로 layout.js라는 파일 이름으로 작성됩니다.
- Layouts는 경로(route)와 관련이 있으며, 특정 경로에 대한 공통된 레이아웃 구조와 스타일을 정의합니다.
- Layouts는 여러 페이지에서 재사용될 수 있습니다.
- 레이아웃 파일은 React 컴포넌트로 작성되며, 해당 컴포넌트는 children prop을 통해 자식 레이아웃이나 페이지 컴포넌트를 감쌀 수 있습니다.
- 레이아웃은 특정 경로 또는 경로 세그먼트에 대해 공유되며, 라우트 간에 상태를 유지합니다.
- 주로 페이지의 공통된 헤더, 푸터, 사이드바 등을 포함하는 데 사용됩니다.
Templates:
- Templates는 각 자식 레이아웃(layout) 또는 페이지(page)를 감싸기 위한 파일입니다.
- 각각의 자식 요소에 대해 새로운 인스턴스를 생성하여 페이지 탐색마다 독립적인 환경을 제공합니다.
- 일반적으로 template.js라는 파일 이름으로 작성됩니다.
- Templates은 특정 동작을 위해 사용될 수 있습니다. 예를 들어, CSS 애니메이션, useEffect나 useState를 활용한 기능, 기본 프레임워크 동작의 변경 등에 유용합니다.
- 레이아웃과 달리 Templates는 페이지 탐색마다 새로운 인스턴스를 생성하고 DOM 요소를 다시 생성하며, 상태는 보존되지 않습니다.
- Templates는 주로 특정 페이지 전환 시 애니메이션 효과를 적용하거나, 특정 페이지에서만 필요한 기능을 관리하는 데 사용됩니다.
Layouts는 레이아웃의 구조와 스타일을 정의하고, 여러 페이지에서 재사용할 수 있는 반면, Templates은 각 페이지 탐색마다 독립적인 환경을 제공하여 특정 동작을 구현하거나 변경할 수 있습니다.
2. SEO를 적용하기 위해 <title> 및 <meta>와 같은 <head> 태그를 루트 레이아웃에 수동으로 추가하는 것이 아니라 layout.js 또는 page.js 파일에서 메타데이터 객체 또는 generateMetadata 함수를 내보내서 정의할 수 있는 구조라 직관적으로 SEO를 관리 할 수 있을거 같습니다. 또한 generateMetadata함수를 통해 동적으로 메타데이터를 관리할 수 있어서 SEO기능 고도화를 이루어 낼 수 있을듯 합니다.
참조
'기억보단 기록을 > Next JS (App Router)' 카테고리의 다른 글
[NextJS 13] Routing - Route Groups (0) | 2023.06.04 |
---|---|
[NextJS 13] Routing - Linking and Navigating (0) | 2023.06.03 |
[NextJS 13] Routing - Defining Routes (0) | 2023.05.30 |
[NextJS 13] Routing - Routing Fundamentals (0) | 2023.05.30 |
[NextJS 13] Getting Started - React Essentials (0) | 2023.05.28 |