[Next.JS] _app.js, _document.js

2023. 2. 15. 20:39·Next.JS
반응형

NextJS 로고

_app.js, _document.js

이 파일들은 pages폴더에 위치한 Next.JS에서 제공하는 로직을 override하기 위해 필요한 파일들이다. Next.JS에서 제공해 주는 기능만 사용한다면 생성하지 않아도 된다. 하지만 실제로 개발하다 보면 100% 커스텀해야 한다.

_app.js

  • _app은 모든 페이지에 레이아웃 형태로 항상 적용되어 있다.
  • 페이지 이동 시에 상태가 변하지 않는다.
  • 필요한 초기 데이터를 getInitialProps에서 받아 컴포넌트들에 공유할 수 있다.
  • global css를 추가하기 좋은 파일이다.
// _app.ts
const App = ({Component, pageProps}: AppProps) => {
  return <Component {...pageProps} />}
}

export default App;
  • 위 코드에서 Component는 활성 중인 page다. 그래서 route간 이동할 때마다 Component는 항상 새 페이지로 교체된다.
  • pageProps는 `App.getInitialProps`를 이용하여 prefetching된 데이터를 받을 수 있다. 데이터가 없다면 빈 객체({})가 내려온다.

 

주의점

  • _app 에서는 Next.JS의 getStaticProps, getServerSideProps와 같은 Data Fetching methods가 동작하지 않는다.
  • server only file이며, Next.JS Server에서 사용함으로 Client에서 사용하는 로직 (eventListener의 window/ DOM로직)을 사용하면 안 된다. (window is not defined 에러 발생)
  • 만약 getInitialProps를 _app에 사용하면 SSG의 효과가 없어 모든 페이지에 Automatic Static Optimization를 할 수 없다.
  • 만약 _app에서 getInitialProps를 사용해야 한다면, `next/app`에서 App객체의 InitialProps를 통해 데이터를 가져와야 한다.

 

실제 사용 예제

getInitialProps를 이용하여 _app에서 특정 api를 호출 후, index.ts에 그 결과 값을 전달하는 로직을 만들어보자. 

// _app.ts

interface DogProps {
    message: string,
    status: string
}

const CustomApp = ({Component, pageProps}: AppProps) => {
    return <Component {...pageProps} />
}

CustomApp.getInitialProps = async (appContext: AppContext) => {
    // 여기서의 App은 next/app 내의 App
    const appProps = await App.getInitialProps(appContext);
    let response = await fetch('https://dog.ceo/api/breeds/image/random');
    let dog: DogProps = await response.json()

    return {pageProps: dog}
}

export default CustomApp;
// index.ts

interface DogProps {
    message: string,
    status: string
}

const Home = (dog: DogProps) => { // _app.ts에서 내려받은 dog값
    return (
        <div>
            {dog.status !== "error" && <img src={dog.message} alt="강아지 사진"/>}
            {dog.status === "error" && <div>에러 발생!</div>}
        </div>
    )
}

export default Home;

 

결과

NextJS 이미지 API 결과
귀여워

 


_document.js

  • _document는 `html`과 `body` 태그를 커스텀하게 만들 수 있다.
  • `,` ``, `
    `
    그리고 ``는 적절한 렌더링을 위해 꼭 필요한 태그들이다.
const Document = () => {
    return (
        <Html lang="en"> // html 태그 커스텀
            <Head/>
            <body className="bg-white">  // body 태그 커스텀
            <Main/>
            <NextScript/>
            </body>
        </Html>
    )
}

export default Document;

주의점

  • _app 에서는 Next.JS의 getStaticProps, getServerSideProps와 같은 Data Fetching methods가 동작하지 않는다.
  • server only file이며, NextJS Server에서 사용함으로 Client에서 사용하는 로직 (eventListener의 window/ DOM로직)을 사용하면 안 된다. (window is not defined 에러 발생)
  • _document의 `` 컴포넌트는 `next/head` 파일 내의 ``컴포넌트와 다르다. `next/document` 파일에서 import 한 것이며, 이는 `` 내의 태그들은 모든 페이지에서 적용될 태그들만 사용해야 한다. 만약 `태그와 같이 페이지마다 다른 값이 보이려면 `next/head`의 ``를 사용해야 한다.
  • `
    `
    외에는 브라우저에서 실행되지 않으므로 비즈니스 로직이 있으면 안 된다.

 

커스텀 renderPage

이는 주로 CSS-in-JS (ex: emotion, styled-component)가 SSR에서 적용되도록 하기 위해서 사용한다.

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

    // 리액트 렌더링 로직
    ctx.renderPage = () =>
      originalRenderPage({
        // 애플리케이션 전체에 적용하기 위한 로직 (_app)
        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

 

References

Next.JS 공식 홈페이지 - https://nextjs.org/docs/advanced-features/custom-app

반응형
저작자표시 동일조건 (새창열림)
'Next.JS' 카테고리의 다른 글
  • [Next.JS] SSG - getStaticPaths
  • [Next.JS] SSG - getStaticProps
  • [Next.JS] SSR - getInitialProps, getServerSideProps
SooJae
SooJae
코드는 효율적으로, 공부는 비효율적으로
    반응형
  • SooJae
    이수재 블로그
    SooJae
  • 전체
    오늘
    어제
    • 분류 전체보기 (60)
      • Spring (8)
      • Next.JS (4)
      • React (3)
      • Angular (1)
      • Language (6)
        • Java (1)
        • Kotlin (1)
        • Javascript (4)
      • Keycloak (5)
      • Knowledge (16)
        • Test (4)
        • Web (9)
        • Security (2)
        • Data Structure (1)
      • Infra (9)
        • Proxmox (2)
        • AWS (0)
        • Kubernetes (3)
      • Tools (1)
        • IntelliJ (1)
      • Algorithm (2)
      • Tistory (4)
      • ETC (1)
  • 블로그 메뉴

    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    스프링 ai
    spring ai
    keycloak
    Functional Programming
    오블완
    javascript
    test
    React
    openAI
    티스토리챌린지
    Auth
    GPT
    ai
    스프링 번역
    Kotlin
    springboot
    ChatGPT
    deepl api
    Next.js
    웹 마스터 도구
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
SooJae
[Next.JS] _app.js, _document.js
상단으로

티스토리툴바