본문 바로가기

넥스트

[next.js] 2. 페이지와 레이아웃

반응형
next.js 공식 문서를 한글로 번역하여 정리한 글이니 자세한 내용은 공식 사이트를 참고 하세요

 

Next.js 13의 App Router는 페이지, 공유 레이아웃 및 템플릿을 쉽게 생성하기 위한 새로운 파일 규칙을 도입했습니다. 이 페이지에서는 이러한 특별한 파일을 Next.js 애플리케이션에서 사용하는 방법을 안내합니다.

 

  페이지

페이지는 특정 라우트에 고유한 UI입니다. page.js 파일에서 컴포넌트를 내보내어 페이지를 정의할 수 있습니다. 중첩된 폴더를 사용하여 라우트를 정의하고, 페이지.js 파일로 해당 라우트에 접근할 수 있게 할 수 있습니다.

 

// app/page.tsx
// app/page.tsx는 / URL의 UI입니다.
export default function Page() {
return <h1>Hello, 홈 페이지!</h1>
}


// app/dashboard/page.tsx
// app/dashboard/page.tsx는 /dashboard URL의 UI입니다.
export default function Page() {
return <h1>Hello, 대시보드 페이지!</h1>
}

 

알아두기
- 페이지는 항상 라우트 하위 트리의 리프입니다.
- .js, .jsx 또는 .tsx 파일 확장자를 페이지에 사용할 수 있습니다.
- 라우트 세그먼트를 공개적으로 접근 가능하게 하려면 page.js 파일이 필요합니다.
- 페이지는 기본적으로 서버 컴포넌트입니다만 클라이언트 컴포넌트로 설정할 수 있습니다.
- 페이지는 데이터를 가져올 수 있습니다. 자세한 내용은 데이터 가져오기 섹션을 참조하세요.

 

(개인 정리) 한 app 폴더는 루트 경로이고 app/page.js 인 경우 page.js 는 개발 환경으로 따지면 localhost:5000 으로 접속하면 바로 보이는 메인 화면에 해당한다.  

dashboard 라는 폴더를 생성하면, localhost:5000/dashboard로 접근이 가능해지고, 해당 폴더의 page.js 의 코드가 브라우저에 뿌려지면서 사용자는 이것을 확인할 수 있게 된다.

 

 레이아웃

레이아웃은 여러 페이지 간에 공유되는 UI입니다. 탐색 중에 레이아웃은 상태를 보존하고 상호 작용하며 다시 렌더링되지 않습니다. 레이아웃은 중첩될 수도 있습니다.

레이아웃.js 파일에서 React 컴포넌트를 기본으로 내보내어 레이아웃을 정의할 수 있습니다. 컴포넌트는 children 속성을 받아들여 렌더링 중에 자식 레이아웃(있는 경우) 또는 자식 페이지가 포함됩니다.

// app/dashboard/layout.tsx
import React from 'react';

type DashboardLayoutProps = {
  children: React.ReactNode; // 페이지 또는 중첩된 레이아웃
};

const DashboardLayout: React.FC<DashboardLayoutProps> = ({ children }) => {
  return (
    <section>
      {/* 공유 UI를 여기에 포함, 예를 들어 헤더나 사이드바 */}
      <nav></nav>
      
      {children}
    </section>
  );
};

export default DashboardLayout;

 

알아두기
- 가장 상위의 레이아웃을 루트 레이아웃이라고 합니다. 이 필수 레이아웃은 애플리케이션의 모든 페이지에서 공유됩니다. 루트 레이아웃은 html 및 body 태그를 포함해야 합니다.

- 모든 라우트 세그먼트는 선택적으로 고유한 레이아웃을 정의할 수 있습니다. 이러한 레이아웃은 해당 세그먼트의 모든 페이지에서 공유됩니다.

- 라우트 내의 레이아웃은 기본적으로 중첩됩니다. 각 부모 레이아웃은 하위에 있는 자식 레이아웃을 React children 속성을 사용하여 래핑합니다.

- 특정 라우트 세그먼트를 공유 레이아웃의 범위에서 제외하거나 포함하기 위해 라우트 그룹을 사용할 수 있습니다.
- 레이아웃은 기본적으로 서버 컴포넌트입니다만 클라이언트 컴포넌트로 설정할 수 있습니다.
- 레이아웃은 데이터를 가져올 수 있습니다. 자세한 내용은 데이터 가져오기 섹션을 참조하세요.

- 상위 레이아웃과 그 자식 간에 데이터를 전달하는 것은 불가능합니다. 그러나 라우트에서 동일한 데이터를 여러 번 가져올 수 있으며, React는 자동으로 요청을 중복 처리하여 성능에 영향을 주지 않습니다.

- 레이아웃은 현재 라우트 세그먼트에 액세스할 수 없습니다. 라우트 세그먼트에 액세스하려면 클라이언트 컴포넌트에서 useSelectedLayoutSegment 또는 useSelectedLayoutSegments를 사용할 수 있습니다.

- .js, .jsx 또는 .tsx 파일 확장자를 레이아웃에 사용할 수 있습니다.
- Layout.js 파일과 page.js 파일을 같은 폴더에 정의할 수 있습니다. 레이아웃은 페이지를 래핑합니다.

 

(개인 정리) 간단하게 요약하자면, 레이아웃은 모든 자식 페이지 컴포넌트와 레이아웃이 공통적으로 공유하는 서버 컴포넌트라고 정리된다. 단, 클라이언트 컴포넌트로 설정할 수도 있다(즉, 기본은 서버 컴포넌트, 선택적으로 클라이언트 지정 가능)

레이아웃은 루트 레이아웃이 있고, 자식 레이아웃이 있는데, 루트 레이아웃은 필수적으로 루트 라우팅 경로에 존재해야 하며, 그 외 중첩 라우트 경로에는 선택적으로 레이아웃을 만들어서 사용할 수 있다(즉, 루트는 필수, 하위는 선택). 

루트 레이아웃은 하위 컴포넌트인 페이지와 레이아웃을 모두 랩핑(감아 돌리는)하는 형태로 children 속성에 담는다.

 

 루트 레이아웃 (필수)

루트 레이아웃은 앱 디렉토리의 최상위 수준에서 정의되며 모든 라우트에 적용됩니다. 이 레이아웃을 사용하면 서버에서 반환되는 초기 HTML을 수정할 수 있습니다.

export default function RootLayout({
  children,
}: {
  children: React.ReactNode // 라우트 경로의 모든 중첩 레이아웃, 자식 페이지를 포함하는 리액트 노드
}) {
  return (
  // 루트 레이아웃은 html 과 body는 필수적으로 포함해야 한다.
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

 

알아두기
- app 디렉토리는 반드시 루트 레이아웃을 포함해야 합니다.
- 루트 레이아웃은 <html>  및 <body> 태그를 정의해야 합니다. Next.js는 자동으로 생성하지 않습니다.
- 내장된 SEO 지원을 사용하여 <head> HTML 요소(예: <title> 요소)를 관리할 수 있습니다. 
- 라우트 그룹을 사용하여 여러 루트 레이아웃을 만들 수 있습니다. (https://nextjs.org/docs/app/building-your-application/routing/route-groups#creating-multiple-root-layouts)
- 기본적으로 루트 레이아웃은 서버 컴포넌트이며 클라이언트 컴포넌트로 설정할 수 없습니다.
- 페이지 디렉토리에서 마이그레이션: 루트 레이아웃은 _app.js 및 _document.js 파일을 대체합니다. 마이그레이션 가이드를 확인하세요.

 

  레이아웃 중첩

폴더 내에 정의된 레이아웃(예: app/dashboard/layout.js)은 특정 라우트 세그먼트(예: acme.com/dashboard)에 적용되며 해당 세그먼트가 활성화될 때 렌더링됩니다. 기본적으로 파일 계층 구조 내의 레이아웃은 중첩되며, 이는 레이아웃이 자식 레이아웃을 자신의 children 속성을 통해 래핑한다는 것을 의미합니다.

 


  중첩된 레이아웃

// app/dashboard/layout.tsx

export default function DashboardLayout({
    children,
}: {
    children: React.ReactNode
}) {
   return <section>{children}</section>
}

 

알아두기
루트 레이아웃만  및  태그를 포함할 수 있습니다.

위의 두 레이아웃을 결합하면 루트 레이아웃 (app/layout.js)이 대시보드 레이아웃 (app/dashboard/layout.js)을 래핑하고, 대시보드 레이아웃은 app/dashboard/* 내의 라우트 세그먼트를 래핑할 것입니다.

 

(개인 정리) 쉽게 말해, 루트 레이아웃은 하위 자식 레이아웃을 감싸고, 그 하위 레이아웃은 또 다시 자신의 아래에 있는 자식 레이아웃을 감싸는 형태가 된다는 의미이다. 즉, 계속 중첩된다는 말로 해석된다.


두 레이아웃은 다음과 같이 중첩됩니다:

 

https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts

 

라우트 그룹을 사용하여 특정 라우트 세그먼트를 공유 레이아웃의 범위에서 제외하거나 포함할 수 있습니다.

 

 템플릿

템플릿은 레이아웃과 비슷하게 각각의 자식 레이아웃 또는 페이지를 감싸는 역할을 합니다. 하지만 레이아웃과 달리 템플릿은 각각의 자식 요소마다 새로운 인스턴스를 생성합니다. 사용자가 템플릿을 공유하는 라우트 간에 이동할 때마다 컴포넌트의 새 인스턴스가 마운트되며, DOM 요소가 다시 생성되며, 상태는 보존되지 않으며, 효과는 다시 동기화됩니다.

 

(개인 정리) 쉽게 말해, template 은 레이아웃과 달리 마운트 될 때 마다 새롭게 생성되고, 초기화 된다는 말 인 듯하다.

이러한 특정 동작이 필요한 경우가 있을 수 있으며, 레이아웃보다 템플릿이 더 적합한 옵션일 수 있습니다.

 

예를 들어

- useEffect (예: 페이지 조회 기록 기능) 및 useState (예: 페이지별 피드백 양식)에 의존하는 기능.
- 기본 프레임워크 동작 변경. 예를 들어, 레이아웃 내부의 Suspense 경계는 레이아웃이 처음 로드될 때만 대체 내용을 표시하고 페이지를 전환할 때는 표시하지 않습니다. 그러나 템플릿의 경우 각 탐색마다 대체 내용이 표시됩니다.

 

템플릿은 template.js 파일에서 기본적인 React 컴포넌트를 내보내어 정의할 수 있습니다. 이 컴포넌트는 children 속성을 받아들여야 합니다.

// app/template.tsx

export default function Template({ children }: { children: React.ReactNode }) {
   return <div>{children}</div>
}

// 중첩 관점에서 template.js는 레이아웃과 그 자식 사이에서 렌더링됩니다. 다음은 단순화된 출력입니다:

<Layout>
  {/* 템플릿에 고유한 키가 지정됨에 유의하세요. */}
  <Template key={routeParam}>{children}</Template>
</Layout>
<head> 


// app 디렉토리에서 내장된 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> 태그를 수동으로 추가해서는 안됩니다. 대신 Metadata API를 사용하여 <head> 요소의 스트리밍 및 중복 처리와 같은 고급 요구 사항을 자동으로 처리해야 합니다.

 


(마무리 글)
이제 2 번째 공식 문서 글을 보고 있는데도 next.js 가 일반적인 리액트 라이브러리 보다 세세하면서도 강력한 기능을 제공하고 있는지 알 수 있었다. 특히, 레이아웃의 경우에는 리액트에서는 직접 header 와 foofter 를 활용하여 루트 컴포넌트에 import 한 뒤에 사용해야 했지만, next.js 에서는 루트 경로에 layout.js 파일만 따로 정의해두면 알아서 자식 컴포넌트와 하위 레이아웃을 감싼 형태로 설정되는 점이 좋아 보였다. 특히, 서버 컴포넌트로서 서버에서 미리 만들어진 뒤 클라이언트단에서 뿌려지기 때문에 SEO 문제도 차이나게 개선 가능하다는 점에서 왜 사람들이 next.js 를 배워라고 하는지 알 듯 했다.

 

반응형