styled-components와 SSR

xxziiko·2024년 1월 7일
0

[Trouble Shooting]

목록 보기
1/4
post-thumbnail


Issue

Warning: Prop `className` did not match. Server: "sc-dlniIP gMCSia" Client: "sc-bdnyFh bceHnv"

Nextjs 기반의 프로젝트를 구축 하고 테스트 겸 컴포넌트 하나를 만들었는데 콘솔에 해당 오류가 발생했다. 찾아보니 FOUC Error 였다.



🤔 FOUC란?

  • Flash Of Unstyled Content의 약자
  • 페이지의 스타일시트 정보가 로드 시점에 포함되지 않은 상태로 페이지가 로드되는 현상
  • 화면 깜박임, 스타일의 적용 전과 적용 후가 그대로 화면에 노출된 상태로 변경되는 현상이 나타난다.


원인

CSS-in-JS

styled-components는 대표적인 CSS-in-JS라이브러리이다. 태그가 지정된 템플릿 리터럴(Tagged Template Literals)이라는 ES6 문법을 사용하여 스타일을 지정한다.

Nextjs 의 SSR

Nextjs에서 server-side renderingstatic generation은 pre-rendering방식이라고 한다. 클라이언트 측에서 모든 작업을 수행하는 대신 미리 각 페이지에 대한 HTML을 생성한다.

hydration

하이드레이션이란 리엑트에서 SSR 혹은 SSG을 실행한 HTML 결과물을 받아온 뒤, 브라우저에서 이것을 다시 리액트 트리에 맞게 파싱하는 행위이다. 이 단계에서 렌더링한 결과물이 어떤 컴포넌트인지 확인하고 각 컴포넌트에 걸린 이벤트리스너를 실제 DOM에 걸어주는 동작을 하게 된다.



정리하자면 hydrate 과정에서 스타일을 입히기 전에 렌더링이 되어 스타일이 누락된 화면이 보여지는 것이다.

해결

프로젝트는 Nextjs 13버전을 사용하고 있다.
먼저, next.config.js에서 styled-components 의 SSR 사용을 설정해주었다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  compiler: {
    styledComponents: true,
  },
};

module.exports = nextConfig;


그리고 _document.jsgetInitialProps 에 스타일 시트가 먼저 렌더링 되도록 정의했다.

import Document, {
  DocumentContext,
  Html,
  Head,
  Main,
  NextScript,
} from "next/document";
import { ServerStyleSheet } from "styled-components";

export default 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 lang="en">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}



참고
https://fourwingsy.medium.com/next-js-hydration-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%9D%B4%EC%8A%88-%ED%94%BC%ED%95%B4%EA%B0%80%EA%B8%B0-988ce0d939e7
https://velog.io/@buddle6091/NextJS%EC%97%90%EC%84%9C-React-%EB%95%8C%EC%B2%98%EB%9F%BC-%EB%B0%94%EB%A1%9C-styled-components%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B4-%EB%B0%9C%EC%83%9D%ED%95%98%EB%8A%94-%EC%98%A4%EB%A5%98
https://github.com/vercel/next.js/blob/canary/examples/with-styled-components/pages/_document.tsx

0개의 댓글

Powered by GraphCDN, the GraphQL CDN