6. Error / / 2024. 3. 7. 17:54

[Error] Next14 Styled-Component 에러

728x90

ISSUE

Next.js에서 styled-components로 작성한 Theme Provider를 전달하였더니 다음과 같은 에러가 나타나며 실행이 되지 않았습니다.

next-dev.js 
Warning: Prop `className` did not match. Server: '어쩌구저쩌구' Client: '어쩌구저쩌구'

REASON

NextJS는 초기 렌더링만 서버가 담당(SSR)하고 그 이후에는 서버를 거치지 않은 채 내부 라우팅을 이용해 페이지가 이동되면서 브라우저에서 렌더링(CSR)을 하게 됩니다.

첫 화면 로딩시에는 SSR로 렌더링하면서 오류가 발생하지 않지만 그 이후 부터는 CSR로 렌더링하면서, 서버에서의 클래스명과 클라이언트에서 클래스명이 달라져서 생기는 오류입니다.

SOLUTION

해결 방법은 두 가지가 있는데, 아래 두가지 방법 중 하나로 해결하면 됩니다. 만일 사용중인 Next.js가 최신 버전이라면 두번째 방법을 사용하는 것을 추천합니다.

💡 NOTE: 두 가지 방법을 동시에 적용하면 바벨이 충돌나서 제대로 작동하지 않습니다.

1️⃣ 첫번째 방법

  1. babel-plugin-styled-components를 설치한다.
npm install --save-dev babel-plugin-styled-components
yarn add --dev babel-plugin-styled-components // --dev : Add a package as a dev dependency
  1. 프로젝트 루트에 .babelrc를 생성한 뒤 설정을 추가하고, 서버를 재실행합니다.
// .babelrc
{
  "presets": ["next/babel"], // -> 이거 설정안하면 빌드안됨
  "plugins": [
    [
      "babel-plugin-styled-components",
      {
        "ssr": false
      }
    ]
  ]
}
  1. _document.tsx에 다음의 내용을 넣어줍니다.
// pages/_document.tsx
import Document, { DocumentContext, DocumentInitialProps } from 'next/document'
import { ServerStyleSheet } from 'styled-components'

export default class MyDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext
  ): Promise<DocumentInitialProps> {
    const sheet = new ServerStyleSheet()
    const originalRenderPage = ctx.renderPage

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        })

      const initialProps = await Document.getInitialProps(ctx)
      return {
        ...initialProps,
        styles: [
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>,
        ],
      }
    } finally {
      sheet.seal()
    }
  }
}

Reference

 

2️⃣ 두번째 방법

Next.js 최신 버전에서는 styled-components의 ssr를 잘 지원해주므로, Next.js의 컴파일러 옵션만으로 간단하게 해결할 수 있습니다.

// next.config.mjs

/** @type {import('next').NextConfig} */
const nextConfig = {
  compiler: {
    // ssr and displayName are configured by default
    styledComponents: true,
  },
};

export default nextConfig;

Reference

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유