[Next.js] styled-components 사용하기


styled-component를 사용할 경우 커스텀이 필요하다.

Next.js - styled-components?

해당 코드를 추가해주어야 SSR시에 styled가 헤더에 주입된다.추가해주지 않으면 CSS가 적용되지 않고 먼저 렌더링되는 현상이 발생한다.

생략부분에는 메타태그를 넣어주거나 웹폰트를 preload 시켜줄 수 있다.

_document.js

import React from "react";
import Document, { Main, NextScript, Head } from "next/document";
import Helmet from "react-helmet";
import { ServerStyleSheet } from "styled-components";

class MyDocument extends Document {
  static async getInitialProps(context) {
    const initialProps = await Document.getInitialProps(context)
    const sheet = new ServerStyleSheet();
    const page = context.renderPage(App => props =>
      sheet.collectStyles(
        <>
          <App {...props} />
        </>
      )
    );
    const styleTags = sheet.getStyleElement();
    return {...initialProps, ...page, helmet: Helmet.renderStatic(), styleTags};
  }
  render() {
    const { htmlAttributes, bodyAttributes, ...helmet } = this.props.helmet; // helmet으로 부터 받아온다.
    const htmlAttrs = htmlAttributes.toComponent();
    const bodyAttrs = bodyAttributes.toComponent();
    return (
      <html {...htmlAttrs}>
        <Head>
          {this.props.styleTags}
          {Object.values(helmet).map(el => el.toComponent())}
        </Head>
        <body {...bodyAttrs}>
          <Main />
          <NextScript />
        </body>
      </html>
    );
  }
}

export default MyDocument;

.babelrc

최초 SSR 이후 CSR로 라우팅을 하게 되는데,이 때 서버에서 생성하는 해시값과 브라우저에서 생성하는 해시값이 서로 달라서 에러가 발생하게 된다.(Prop className did not match)

이를 해결하기 위해 바벨 플러그인을 설치

{
  "presets": ["next/babel"],
  "plugins": [
    [
      "babel-plugin-styled-components",
      {
        "fileName": true,
        "displayName": true,
        "pure": true
      }
    ]
  ]
}

fileName : 코드가 포함된 파일명을 알려줌

displayName : 클래스명에 해당 스타일 정보 추가pure : 사용하지 않은 속성 제거