hiro08gh

ソフトウェアに関すること

Next.jsにstyled-componentsを導入する

こんにちはかみむらです。もしReactベースのフレームワークで、スタイルを構成する場合はCSS in JSライブラリを検討する思います。特に人気なのが、styled-componentsです。最近では採用しているプロダクトが増えてきています。

自分もstyled-componentsを利用する一人ですが、Next.jsで導入する場合少し癖があったので備忘録として残しておきます。


ドキュメント
styled-components: Documentation

前提

TypeScriptベースで話を進めていきます。

Next.jsにTypeScriptを導入する記事はこちら
code-log.hatenablog.com

styled-componentsのインストール

まずは、ライブラリをインストールします。

$ yarn add styled-components

そして、TypeScriptsに対応する必要があるので、別途インストールが必要です。

$ yarn add -D @types/styled-components

styled-componentsの設定

_documentファイルは通常htmlとbodyを拡張するために使われます。ここではstyled-componentsで出力されるファイルを、Headタグで読み込む設定をしています。これを設定しないと、初期表示でスタイルが読み込まれるのが若干遅れます(Netlifyで観測)。

_documentファイルのドキュメントはこちらです。
Advanced Features: Custom `Document` | Next.js

_document.tsx

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

type Props = {
  styleTags: any;
};

export default class MyDocument extends Document<Props> {
  static getInitialProps({renderPage}) {
    const sheet = new ServerStyleSheet();

    const page = renderPage(App => props =>
      sheet.collectStyles(<App {...props} />),
    );

    const styleTags = sheet.getStyleElement();

    return {...page, styleTags};
  }

  render() {
    return (
      <Html lang="ja">
        <Head>
          <meta charSet="utf-8" />
          {this.props.styleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

_document.tsxの書き方はこちらの記事を参考にしました。
Next.js + Styled Components The Really Simple Guide ▲ + 💅 - DEV

babel-plugin-styled-components

そして、styled-componentsのbabelプラグインをインストールします。

$ yarn add -D babel-plugin-styled-components

.babelrcファイルを作成して、下記の設定をして下さい。
.babelrc

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

www.styled-components.com

displayNameをfalseにしていると、classの命名がランダムな文字列で出力されます。ただ、これはデバッグがしづらいため、もし開発環境で使う場合はtrueにすることをお勧めします。

//displayNameをtrueにした場合
<div class="sc-AykKC itxLzi">test</div>

//displayNameをfalseにした場合
<div class="pages__H1-sc-AykKC itxLzi">test</div>

ThemeProviderの利用

styled-componentsにはThemeProviderというAPIがあります。これはContext APIを使って、子のコンポーネントに、propsでスタイルを渡すことができます。これで、スタイルを共通化することができます。ThemeProviderは、_app.jsで使用します。

components/_app.tsx

import { AppProps } from 'next/app';
import { ThemeProvider } from 'styled-components';
import { theme } from '@/styles/theme';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ThemeProvider theme={theme}>
        <Component {...pageProps} />
    </ThemeProvider>
  );
}

export default MyApp;

そして、Layout.tsxをインポートします。これでThemeProviderが使えるようになります。

pages/index.tsx

import Layout from '../components/Layout';

const Home = () => {
  return (
    <>
      <H1>Home</H1>
    </>
  )
}

const H1 = styled.h1`
  //propsで、themeのmainにある"red"を渡している
  color: ${props => props.theme.main}
`

最後に

Reactと違って、Next.jsではstyled-componentsを導入するのが若干難しかったです。Next.jsでコンポーネント志向なスタイルをする場合、CSS in JSは非常に有効な手段です。Next.jsでアプリケーションを作成する場合は、ぜひ導入してみて下さい。