Docs
Routing
Pages and Layouts

Pages and Layouts

페이지 라우터는 페이지 개념에 기반한 파일 시스템 기반 라우터를 가지고 있습니다.

pages 디렉토리에 파일을 추가하면 자동으로 라우트로 사용 가능해집니다.

Next.js에서 페이지pages 디렉토리의 .js, .jsx, .ts, 또는 .tsx 파일에서 내보내진 React 컴포넌트 (opens in a new tab)입니다. 각 페이지는 파일 이름을 기반으로 한 라우트와 연결됩니다.

예시: 아래와 같이 React 컴포넌트를 내보내는 pages/about.js를 생성하면, /about에서 접근할 수 있습니다.

export default function About() {
  return <div>About</div>
}

Index routes

라우터는 index라는 이름의 파일을 디렉토리의 루트로 자동 라우팅합니다.

  • pages/index.js/
  • pages/blog/index.js/blog

Nested routes

라우터는 중첩 파일을 지원합니다. 중첩 폴더 구조를 생성하면 파일들이 여전히 같은 방식으로 자동 라우팅됩니다.

  • pages/blog/first-post.js/blog/first-post
  • pages/dashboard/settings/username.js/dashboard/settings/username

Pages with Dynamic Routes

Next.js는 동적 라우트를 가진 페이지를 지원합니다. 예를 들어, pages/posts/[id].js라는 파일을 생성하면, posts/1, posts/2 등에서 접근할 수 있습니다.

동적 라우팅에 대해 더 알아보려면 동적 라우팅 문서를 확인하세요.

Layout Pattern

React 모델을 사용하면 페이지를 여러 컴포넌트로 분해할 수 있습니다. 이 컴포넌트들은 종종 페이지 간에 재사용됩니다. 예를 들어, 모든 페이지에 같은 네비게이션 바와 푸터를 가질 수 있습니다.

components/layout.js
import Navbar from './navbar'
import Footer from './footer'
 
export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}

Examples

Single Shared Layout with Custom App

전체 애플리케이션에 하나의 레이아웃만 있는 경우, 커스텀 앱을 생성하고 애플리케이션을 레이아웃으로 감쌀 수 있습니다. 페이지 변경 시 <Layout /> 컴포넌트가 재사용되므로 컴포넌트 상태가 유지됩니다(예: input values).

pages/_app.js
import Layout from '../components/layout'
 
export default function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}

Per-Page Layouts

여러 레이아웃이 필요한 경우, 페이지에 getLayout 속성을 추가하여 레이아웃을 반환할 수 있는 React 컴포넌트를 지정할 수 있습니다. 이를 통해 페이지별로 레이아웃을 정의할 수 있습니다. 함수를 반환하므로 원하는 경우 복잡한 중첩 레이아웃을 가질 수 있습니다.

pages/index.js
 
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
 
export default function Page() {
  return (
    /** 여기에 내용을 넣으세요 */
  )
}
 
Page.getLayout = function getLayout(page) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}
pages/_app.js
export default function MyApp({ Component, pageProps }) {
  // 가능하다면, 페이지 수준에서 정의된 레이아웃을 사용하세요
  const getLayout = Component.getLayout ?? ((page) => page)
 
  return getLayout(<Component {...pageProps} />)
}

페이지 간에 이동할 때, 단일 페이지 애플리케이션(SPA) 경험을 위해 페이지 상태(입력 값, 스크롤 위치 등)를 유지 하고자 합니다.

이 레이아웃 패턴은 페이지 전환 사이에 React 컴포넌트 트리가 유지되므로 상태 유지를 가능하게 합니다. 컴포넌트 트리를 통해 React는 어떤 요소가 변경되었는지 파악하여 상태를 보존할 수 있습니다.

알아두면 좋습니다: 이 과정을 재조정 (opens in a new tab)이라고 하며, React가 어떤 요소가 변경되었는지 이해하는 방법입니다.

With TypeScript

타입스크립트를 사용할 때는 먼저 getLayout 함수를 포함하는 페이지의 새 타입을 생성해야 합니다. 그런 다음, 이전에 생성된 타입을 사용하도록 Component 속성을 오버라이드하는 AppProps의 새 타입을 생성해야 합니다.

pages/index.tsx
import type { ReactElement } from 'react'
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
import type { NextPageWithLayout } from './_app'
 
const Page: NextPageWithLayout = () => {
  return <p>hello world</p>
}
 
Page.getLayout = function getLayout(page: ReactElement) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}
 
export default Page
pages/index.js
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
 
const Page = () => {
  return <p>hello world</p>
}
 
Page.getLayout = function getLayout(page) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}
 
export default Page
pages/_app.tsx
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
 
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode
}
 
type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout
}
 
export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  // 가능하다면, 페이지 수준에서 정의된 레이아웃을 사용하세요
  const getLayout = Component.getLayout ?? ((page) => page)
 
  return getLayout(<Component {...pageProps} />)
}
pages/_app.js
export default function MyApp({ Component, pageProps }) {
  // 가능하다면, 페이지 수준에서 정의된 레이아웃을 사용하세요
  const getLayout = Component.getLayout ?? ((page) => page)
 
  return getLayout(<Component {...pageProps} />)
}

Data Fetching

레이아웃 내에서 useEffect 또는 SWR (opens in a new tab) 같은 라이브러리를 사용하여 클라이언트 측에서 데이터를 가져올 수 있습니다. 이 파일이 페이지가 아니기 때문에 현재 getStaticPropsgetServerSideProps는 사용할 수 없습니다.

components/layout.js
import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'
 
export default function Layout({ children }) {
  const { data, error } = useSWR('/api/navigation', fetcher)
 
  if (error) return <div>Failed to load</div>
  if (!data) return <div>Loading...</div>
 
  return (
    <>
      <Navbar links={data.links} />
      <main>{children}</main>
      <Footer />
    </>
  )
}