Next 공식 문서에 기재된
page, shared layout, template 개념과 구현 방법을 소개한다.
앞선 시리즈의 글 외에도 다음 내용에 대한 이해가 있다면 좋다.
핵심은 다음과 같다.
Next는 자체 Caching 솔루션을 기반으로
빌드 시점에 정적으로 생성된 페이지를 캐싱했다가 반환한다.
위와 같이 Next는 기본적으로 모든 컴포넌트를 Server Component의 형태로 지원하고, 'use client'을 명시하면 이를 Client Component로 변환해준다.
'use client' 또는 'use server' convention을 사용하면 해당 페이지를 기점으로 포함된 모든 컴포넌트들이 동일한 방식으로 렌더링된다.
렌더링 방식을 유지하기 위한 특수한 패턴(#1 | #2)을 활용할 수 있다.
하나의 Route Segment에는 한 개 이상의 Page가 존재할 수 없다.
할당하는 방법은 구조화된 폴더에 page 파일을 배치하는 것이다.
페이지는 Route Subtree에서 항상 leaf, 최하위 컴포넌트에 해당된다.
바꿔 말하자면, 이를 포함하는 상위 컴포넌트에서 동기적인 지연이 발생하지 않도록 주의해야 한다.
app/dashboard/page.tsx
// `app/dashboard/page.tsx` is the UI for the `/dashboard` URL export default function Page() { return <h1>Hello, Dashboard Page!</h1> }
다양한 페이지에 적용되는 공통의 UI를 정의한다.
공통의 레이아웃에 대해서는 re-render가 발생하지 않는다.
따라서, 상태도 유지되고, 추가적인 hydration도 발생하지 않는다.
layout 파일에서 React Component를 default export하여 정의한다.
layout 내에 포함될 page는 children props를 통해 전달한다.
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> ) }
parallel routing을 통해 다수의 page를 포함시킬 수 있다.
각 segment는 자체 layout을 보유할 수 있다.
즉, 중첩된 segment 각각에 layout을 정의하면 layout도 중첩된다.
client component로 정의할 수 있고, data fetch도 가능하다.
레이아웃은 기본적으로 하위 세그먼트에 접근할 수 없다.
이러한 기능은 Client Component로 전환하여 useSelectedLayoutSegment
또는 useSelectedLayoutSegments
훅을 사용해야 한다.
모든 레이아웃에 공통적으로 적용되는 파일
<html>
과 <body>
태그를 포함해야 한다.
Multi Root Layout 패턴
페이지 별로 다른 메타태그를 설정하거나, 외부 라이브러리의 활용을 위해 <head>
와 <body>
에 script 번들을 위한 코드를 선택적으로 주입하여 JavaScript 번들 사이즈를 축소시키기 위한 용도로 사용할 수 있다.
app
폴더는 반드시 Root Layout을 포함하고 있어야 한다.
그리고 Root Layout은 반드시 <html>
과 <body>
태그를 정의해야 한다.
<head>
에 작성했던 메타 태그는 built-in SEO 기능으로 대체할 수 있다.
일반 Layout과는 달리 Root Layout은 Client Component로 사용할 수 없다. 이러한 설계는 CSR을 사용하더라도 SEO가 가능하도록 돕는다.
Router 트리의 최상위 노드인 app 세그먼트의 layout은 Root Layout이고,
그 하위 세그먼트인 dashboard의 레이아웃은 중첩된 형태로 위치하게 된다.
app/dashboard/layout.tsx
export default function DashboardLayout({ children, }: { children: React.ReactNode }) { return <section>{children}</section> }
layout과 비슷하게 page를 감싸는 UI를 정의하며,
template 파일에 작성하게 된다.
차이점은 다음과 같다.
layout의 하위 컴포넌트로 위치된다.
layout은 최초 렌더링 이후 상태를 유지하지만,
template은 routing에 따라 매번 새로운 인스턴스를 생성한다.
바꿔 말하면, routing에 따라
2-1. 새로운 컴포넌트가 마운트되고,
2-2. DOM element도 재생성되고,
2-3. state는 유지되지 않고,
2-4. effect도 다시 동기화된다.
즉, 기존 layout은 최초 렌더링 이후 다시 렌더링되지 않아 성능적인 측면에서 최적화되어 있지만, 상호작용에 따라 변화해야 한다면 오히려 그러한 정적인 특성이 방해가 되기 때문에 만들어진 개념이라고 생각하면 된다.
다음과 같은 상황에서 사용하기 좋다.
<head>
기존 html 문서에서 head 태그에 정의했던 내용들은 이제 별도로 관리된다.
그러니 head 태그에 직접 정의하는 방식은 지양해야 한다.
사용 방식은 다음과 같다.
1. layout 또는 page 파일에서 generateMetadata 함수를 사용하거나
2. 아래 코드와 같이 Metadata 객체를 export한다.
app/page.tsx
import { Metadata } from 'next' export const metadata: Metadata = { title: 'Next.js', } export default function Page() { return '...' }
link 또는 navigation 기능을 통해 원하는 세그먼트에 접근하는 방법을 익히게 된다.
컴포넌트의 속성(Server/Client)에 따라 알맞은 방법을 사용할 수 있다.
Terminology
Defining Routes
Pages and Layouts
Linking and Navigating
Route Groups
Dynamic Routes
Loading UI and Streaming
Error Handling
Parallel Routes
Intercepting Routes
Route Handlers
Middleware
Project Organization
Internationalization
레이아웃에서
6. client component로 정의할 수 있고, data fetch도 가능하다.
에 대해 추가적인 설명이 가능할까요? 그냥 레이아웃에서도 data fetch가 가능하단 말인가요?