next.js에 styled-components 적용 고군분투기. by. react-bird

김수정·2020년 1월 3일
2

Intro

이전부터 프로젝트에 styled-components를 편하게 잘 사용하고 있기도 했고, 강의도 마침 이 플러그인을 사용하였습니다. 다만 강의는 무지 뒤편에서 이 플러그인을 적용시키는데 저는 아직 거기까지 강의를 보지 않았기 때문에 (-.-) 적용하는데 뭔 문제있겄나.. 하고 넣었다가 엄청 헤맸네요. antd와 styled-components 적용기 시작합니다!

설치

우선 설치를 해야겠죠.

npm i antd styled-components

사용

강의에서는 nav 컴포넌트를 따로 만들지 않았는데 저는 나누고 싶어서 나눴습니다. -.- 왜냐면 layout 컴포넌트는 안에 있는 컴포넌트들의 배치 기능만 하도록 하고 싶었기 때문이죠.

// base
import React from 'react';
import Link from 'next/link';
import styled from 'styled-components'; // (1)

// screen
import { Input, Menu } from 'antd';

// (2)
const SearchButton = styled(Input.Search)`
  vertical-align: middle;
  & .anticon {
    margin: 0;
  }
`;

const Nav = () => (
  <div>
    <Menu mode="horizontal">
      <Menu.Item key="home"><Link href="/"><a>리액트버드</a></Link></Menu.Item>
      <Menu.Item key="profile"><Link href="/profile"><a>프로필</a></Link></Menu.Item>
      <Menu.Item key="mail">
        <SearchButton enterButton /> // (3)
      </Menu.Item>
    </Menu>
  </div>
);

export default Nav;

적용 방법 자체는 기존 react 프로젝트에서 적용하는 것과 다를 게 없었습니다.
(1) import로 styled를 불러옵니다.
(2) 해당 dom을 가리키는 변수명을 만들고 일반 태그라면 styled.div``;로 작성하고
antd 컴포넌트일 경우에는 styled.(antdComponent)``;로 작성합니다.
(3) 해당 dom을 변수명으로 변경합니다.

style 적용이 안됨

styled component를 작성해서 자동으로 브라우저에서 바뀐 코드가 적용될 때는 적용이 되는데... 새로고침하면 style이 적용이 안되었습니다. 그 때 콘솔에서는 영어로 서버의 class-name과 클라이언트의 class-name이 다르다고 떴습니다.

구글링을 해보니 babel이 리로드가 되지 않아서라고 하네요. 음.. 강의에서는 맨 끝부분의 코드를 봐도 babel.rc가 없었지만 제가 적용이 안되니 어쩌겠어요. babel.rc를 추가했습니다.

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

오, 적용은 됐습니다. 그런데 스타일 컴포넌트로 적용한 css는 렌더링 될 때마다 스타일이 적용되는 게 브라우저에 다 보였습니다....

스타일 렌더링이 느림

styled-components는 javascript여서 javascript 렌더링 순서에서 렌더링이 되어 유저 눈에 스타일 적용되는 게 다 보였던 겁니다.. 리액트에선 이런 문제 없었는데 -.-...
검색하다 또 찾게된 방법
_document.js를 만들어 아래 내용을 넣는 것입니다.
수업에서는 _app.js만 있고 _document.js가 없는데 원래 index.html 역할을 하는 곳이 _document.js 파일이다보니 _app.js에 있던 것도 옮겨주었습니다.

import Document, {
  Html, Head, Main, NextScript,
} 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} />),
      });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }

  render() {
    return (
      <Html>
        <Head>
          <style />
          <link 
      		rel="stylesheet" 
      		href="https://cdnjs.cloudflare.com/ajax/libs/antd/3.16.2/antd.css" />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

<title>은 _document.js에 넣으면 안됩니다. 각 페이지마다 제목이 다를 수도 있고 next.js에서 금하고 있습니다.

profile
정리하는 개발자

1개의 댓글

comment-user-thumbnail
2021년 1월 7일

감사합니다! 도움많이됐어요!

답글 달기