Next.js TS 리렌더링시 Styled-Components 적용 안되는 에러

gusdas·2022년 7월 13일
0

에러노트

목록 보기
19/22
post-custom-banner

에러

Next와 styled-components를 쓰게 되면 브라우저 로딩이 끝나야 CSS 적용이 되거나 새로고침을하게되면 css가 적용이 안된다.

이유

Next가 먼저 정적으로 생성된 HTML을 렌더후 나머지 JS파일을 로드하게 된다.
JS에 의해 동적으로 CSS가 생성되는 CSS-In-Js 방식인 styled-components는 위와 같은 과정에서 생성되는 HTML에 우리의 코드가 함께 빌드 되지않는다.

자세한 설명은 이 블로그를 참고하길 바란다.

해결법

renderPage 함수를 커스터마이징을 통해 해결해야한다.
renderPage 함수 커스터마이징은 반드시 CSS-In-Js 방식 사용 할때만 수정하라고 한다.

앞으로는 next를 사용할 때에는 Sass css-in-css방식을 적용해보아야겠다.

1. page 디렉토리 안에 _document.ts를 생성

import Document, {
    Html,
    Head,
    Main,
    NextScript,
    DocumentContext,
} from 'next/document'

class MyDocument extends Document {
    static async getInitialProps(ctx: DocumentContext) {
        const initialProps = await Document.getInitialProps(ctx)
        return { ...initialProps }
    }

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

export default MyDocument

2. ServerStyleSheet 함수 import

import { ServerStyleSheet } from 'styled-components'

3. renderPage 함수 조건 추가

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()
        }
    }
}

추가에러

여기서 className did not match는 다른 방법으로 해결해야했다.

이유

서버에서 받은 해시+클래스명과 새로고침후 클라이언트에서 받은 해시+클래스명이 달라서 발생하는 문제다.

해결법

1. 바벨 플러그인 설치

npm i babel-plugin-styled-components

2. .babelrc설정

.babelrc를 생성후 아래 코드 작성

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

참고 블로그

profile
웹개발자가 되자
post-custom-banner

0개의 댓글