NextJS: 커스텀 App & Document

hwisaac·2023년 3월 13일
0

Next.js

목록 보기
25/29

Custom App

참고: Next.js 13에서는 app/ 디렉토리(베타)를 도입합니다. 이 새로운 디렉토리는 레이아웃, 중첩 라우트 및 기본적으로 Server Components를 사용할 수 있습니다. app/ 안에서 레이아웃을 포함한 전체 애플리케이션의 데이터를 가져올 수 있으며, 더욱 정교한 중첩 레이아웃(데이터 가져오기를 포함한)을 지원합니다.

app/를 점진적으로 적용하는 방법에 대해 자세히 알아보세요.

Next.js는 페이지를 초기화하기 위해 App 컴포넌트를 사용합니다. 이를 재정의하여 페이지 초기화를 제어할 수 있으며 다음과 같은 작업을 수행할 수 있습니다.

  • 페이지 변경 사이에 레이아웃 유지
  • 페이지 이동 시 상태 유지
  • 페이지에 추가 데이터 주입
  • 전역 CSS 추가
    기본 App을 덮어쓰려면 다음과 같이 ./pages/_app.js 파일을 만듭니다.
export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

Component prop은 활성 페이지입니다. 따라서 라우트 간에 이동할 때마다 Component가 새 페이지로 변경됩니다. 따라서 Component에 보내는 모든 props는 페이지에서 받게됩니다.

pageProps는 초기 프로퍼티가 포함된 객체입니다. 이 프로퍼티는 데이터 가져오기 메소드 중 하나로 페이지에 사전로드된 것입니다. 그렇지 않으면 빈 객체입니다.

App.getInitialPropscontext.ctx라는 단일 인수를 받습니다. 이것은 getInitialPropscontext 객체와 동일한 속성 집합의 객체입니다.

주의 사항

  • 앱이 실행 중이고 커스텀 앱을 추가한 경우 개발 서버를 다시 시작해야 합니다. pages/_app.js가 이전에 없었다면 필요하지 않습니다.
  • 커스텀 앱에서 getInitialProps를 추가하면 정적 생성이 없는 페이지에서 자동 정적 최적화가 비활성화됩니다.
  • 커스텀 앱에서 getInitialProps를 추가할 때는 "next/app"에서 App을 가져와서 getInitialProps 내부에서 App.getInitialProps(appContext)를 호출하고 반환된 객체를 반환 값에 병합해야 합니다.
  • AppNext.js 데이터 가져오기 메소드(getStaticProps 또는 getServerSideProps)를 지원하지 않습니다. 전역 데이터 가져오기가 필요한 경우 app/ 디렉토리를 점진적으로 적용하는 것을 고려하세요.

TypeScript

TypeScript를 사용하는 경우 TypeScript 문서를 참조하세요

Custom Document

참고: Next.js 13app/ 디렉터리를 (베타로) 도입합니다. 이 새 디렉터리는 레이아웃, 중첩된 경로 및 기본적으로 서버 컴포넌트를 사용합니다. app/ 내에서 루트 레이아웃을 사용하여 초기 htmlbody 태그를 수정할 수 있습니다.

app/ 적용에 대해 자세히 알아보기

사용자 정의 Document를 사용하면 페이지를 렌더링하는 데 사용되는 <html><body> 태그를 업데이트할 수 있습니다. 이 파일은 서버에서만 렌더링되므로 onClick과 같은 이벤트 핸들러는 _document에서 사용할 수 없습니다.

기본 Document를 재정의하려면 다음과 같이 파일 pages/_document.js를 만듭니다.

import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

위 코드는 Next.js에서 추가한 기본 Document입니다. 사용자 정의 속성은 프로퍼티로 허용됩니다. 예를 들어 <html> 태그에 lang="en"을 추가할 수 있습니다.

<Html lang="en">

또는 body 태그에 className을 추가할 수 있습니다.

<body className="bg-white">

<Html>, <Head />, <Main /><NextScript />는 페이지가 올바르게 렌더링되기 위해 필요합니다.

주의사항

_document에서 사용하는 <Head /> 컴포넌트는 next/head와 같지 않습니다. 여기서 사용하는 <Head /> 컴포넌트는 모든 페이지에 공통적인 <head> 코드에만 사용해야 합니다. 다른 모든 경우, 예를 들어 <title> 태그와 같은 경우, 페이지나 컴포넌트에서 next/head를 사용하는 것이 좋습니다.
<Main /> 외부의 React 컴포넌트는 브라우저에서 초기화되지 않습니다. 여기에 응용 프로그램 로직이나 사용자 정의 CSS(styled-jsx와 같은)를 추가하지 마십시오. 모든 페이지에서 공유되는 컴포넌트(메뉴 또는 툴바와 같은)가 필요한 경우, 대신 레이아웃(Layouts)을 읽으십시오.
현재 DocumentgetStaticPropsgetServerSideProps와 같은 Next.js 데이터 가져오기 메서드를 지원하지 않습니다.

renderPage 커스터마이징

참고: 이 기능은 CSS-in-JS와 같은 라이브러리가 서버 측 렌더링을 지원하는 경우에만 사용하면 됩니다. 내장 styled-jsx 지원에는 필요하지 않습니다.

React 18 지원을 위해서는 가능하면 getInitialPropsrenderPage를 커스터마이징하지 않는 것이 좋습니다.

아래에 나오는 ctx 객체는 renderPage를 추가한 getInitialProps에서 받는 것과 동일합니다.

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const originalRenderPage = ctx.renderPage

    // React 렌더링 로직을 동기적으로 실행합니다.
    ctx.renderPage = () =>
      originalRenderPage({
        // 전체 React 트리를 래핑하는 데 유용합니다.
        enhanceApp: (App) => App,
        // 각 페이지에 대해 래핑하는 데 유용합니다.
        enhanceComponent: (Component) => Component,
      })

    // 부모 `getInitialProps`를 실행합니다. 이제 사용자 정의 `renderPage`가 포함됩니다.
    const initialProps = await Document.getInitialProps(ctx)

    return initialProps
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument

참고: _documentgetInitialProps는 클라이언트 측 전환 중에 호출되지 않습니다.

TypeScript

TypeScript를 사용하는 경우 내장 DocumentContext 타입을 사용하여 파일 이름을 ./pages/_document.tsx로 변경할 수 있습니다.

import Document, { DocumentContext, DocumentInitialProps } from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext
  ): Promise<DocumentInitialProps> {
    const initialProps = await Document.getInitialProps(ctx)

    return initialProps
  }
}

export default MyDocument

0개의 댓글