본문 바로가기

개발 일지/React

[Next.js] styled-component 적용하기

문제

  • 스타일이 적용되지 않은 html 코드가 먼저 렌더링되는 문제 발생
  • Header 부분 표시하려고 스타일 컴포넌트 적용하니 오류 발생

 

원인

  • 자바스크립트 코드가 적용이 되지 않은 페이지가 미리 렌더링되기 때문에 CSS-in-JS 로 스타일링을 하면 스타일이 적용되지 않은 html 코드가 먼저 렌더링 되는 문제가 발생하게 된다.
  • Next.js는 첫 페이지 로드가 SSR로 동작 ⇒ 서버에서 생성된 컴포넌트와 CSR로 클라이언트에서 생성된 컴포넌트의 클래스명이 서로 달라진다.

해결

  • html 파일에 CSS-in-JS 형식으로 작성된 스타일 요소들을 주입시켜서 스타일이 적용되지 않은 html 코드가 먼저 렌더링되는 문제를 해결할 수 있다.
  • Next.js에서 styled-components를 사용할 때 ⇒ **_document**를 따로 설정해서 SSR될 때 CSS가 head에 주입되도록 만든다.
  •  
import Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext
} from 'next/document';
import { ServerStyleSheet } from 'styled-components';

class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    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();
    }
  }

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

export default MyDocument;
  • 환경에 따라 달라지는 className을 일관되게 해주는 라이브러리 설치
npm install --save-dev babel-plugin-styled-components
  • 루트 디렉토리에 .babelrc 파일 생성
{
  "presets": ["next/babel"],
  "plugins": [
    [
      "babel-plugin-styled-components", 
      {
        "ssr": true, // SSR을 위한 설정
        "displayName": true, // 클래스명에 컴포넌트 이름을 붙임
        "pure": true // dead code elimination (사용되지 않는 속성 제거)
      }
    ]
  ]
}

 

참고 자료

https://velog.io/@eunnbi/NextJS-styled-components와-함께-사용하기

https://mniyunsu.github.io/nextjs-styled-component-setting/

https://tesseractjh.tistory.com/164