Next.js에서 Styled-components사용할 때 그리고 GlobalStyle의 함정 (feat.Flickering&Font)

SMG·2020년 8월 24일
6

Next.js

목록 보기
1/1

styled-components는 쓰면 쓸수록 진국이다.

재밌고 편리하고 재활용 가능한 기능들도 꽤나 있고, 까도까도 재밌는 것만 나오는 양파같은 스탈컴포넌ㅌ.

물론 css-in-js중 에서 점유율이 조금씩 떨어지고 있지만..

회사에서 Next.js 를 사용하기로 결정이 된 후

React를 할 때와 마찬가지로 styled-components를 적용 했는데

이게 웬걸 ..

화면들이 엄청나게 깜빡 거리는 것이다.

Next.js에 Styled-components를 적용하면 깜빡이는 이유?

Next.js는 SSR로서 서버에서 Meta태그 등이 포함되어 있는 HTML을 먼저 만들어놓고 보여준 후 자바스크립트를 동적으로 추가 시켜주어 것인데, css-in-js인 styled-components는 당연하게도 HTML 생성 이후에 적용이 되는 "JS"이기 때문에 깜빡! 거릴 수 밖에 없었다 .

어떻게 해결 하나 ?

Next.js에서는 기본적으로 보이지는 않지만 _app.js와 _document.js가 있다.

이 파일들을 생성해서 수정하면 custom하게 사용이 가능하다.

_document.js를 pages폴더에 생성한 후,

다음과 같은 코드를 입력하자.

import Document from "next/document";
import { ServerStyleSheet } from "styled-components";

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;
    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />), //ServerStyleSheet를 사용해 정의된 모든 스타일을 수집하여 페이지가 렌더링되기 전에 props로 채워지도록 반환한다.
        });
      const initialProps = await Document.getInitialProps(ctx);

      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}

주의할 점 : _document.js는 서버사이드 렌더링만 가능하며 React의 기능들을 사용할 수 없다.

babel plugin 을 설치하자.

yarn add -D babel-plugin-styled-components

그후 루트 폴더에 .babelrc 파일을 만들어서 다음 코드를 입력하자.

{
  "presets": [
    "next/babel"
  ],
  "plugins": [
    [
      "styled-components",
      {
        "ssr": true,
        "displayName": true,
        "preprocess": false
      }
    ]
  ]
}

여기까지는 알 . 겠 . 는 . 데 자꾸 깜빡 거린다.

이유를 계속 찾았지만 계속해서 깜빡이다가!

오늘이 되어서야 이유를 찾았다.

개발자도구에 Network tab을보니 re-render가 될때 마다, Font파일들이 reload되는 것이다.

휴.... 그래도 원인을 발견해서 다행이었다.

기존에는 이런식으로 GlobalStyle에 font-face들을 넣어주고 다른 style들을 적용하듯이

이런식으로 _app.js에 적용해 주었다.

그래서 방법이 뭐냐고 .... 폰트를 뺄 순 없었다. 그래서 구글링을 계속한 결과... 두둥...

GlobalStyle에서 나오는 그런 오류? 같은 것 같다.(확실힌 모름 .. )

결국 font-face들을 빼고 모두 템플릿 리터럴에 담은후


이런식으로 _app.js의 style태그안에 담게 되었다.

원래는

<style jsx global>

을 사용하려고 했으나, 계속해서

위와 같은 오류가 발생해서 결국 <style>태그안에 감싸고 모든 깜빡임이 해결 되었다.

3개의 댓글

comment-user-thumbnail
2020년 10월 20일

안녕하세요 좋은 해결방법 감사합니다. 저 같은 경우는 로 넣으면 싱글쿼트가 치환되서 폰트 로드가 안됐습니다. 그래서 <style dangerouslySetInnerHTML={{ __html: fontFace }} />로 변경해주니까 되네용!

1개의 답글
comment-user-thumbnail
2021년 8월 25일

저도 특정 액션이 일어날때마다 폰트가 다운로드 되는 현상이 있었는데 이 글보고 해결할수 있었네요. 감사합니다! (정확히 1년전 글 이라는게 소름 ㄷㄷ)

답글 달기