Next.js で Material-UI と styled-components を使う #nextjs

概要

Next.js で Material-UI を利用しつつ、 styled-components でカスタマイズできる環境を構築した記録。

nextjs.org

material-ui.com

styled-components.com

Next.js でプロジェクトを作る

$ npx create-next-app

Material-UI を install する

$ npm install @material-ui/core

styled-components を install する

$ npm install styled-components

babel-plugin-styled-components を install する

これを入れないと Warning: Prop className did not match. とか言われる。

$ npm install --save-dev babel-plugin-styled-components

.babelrc を(なければ)作成して、設定する。

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

github.com

_app.js で優先順位を調整する

styled-components が最後に当たるようにするには、CSS injection order を設定しておくらしい。

Style Library Interoperability - Material-UI

<StylesProvider injectFirst> で Component ツリーを囲んでおく。

CssBaseline は reset.css 的なやつらしい。

import '../styles/globals.css'
import {StylesProvider} from "@material-ui/core";

function MyApp({Component, pageProps}) {
    return (
        <StylesProvider injectFirst>
            <CssBaseline/>
            <Component {...pageProps} />
        </StylesProvider>
    )
}

export default MyApp

_document.js を作成して修正する

material-ui や styled-components を Next.js で使うには、 pages/_document.js をカスタマイズする必要がある。

(なければ)ファイルを新規に作成し、どちらも公式の example があるので、参考にしながらいい感じにマージする。

material-ui/_document.js at master · mui-org/material-ui · GitHub

next.js/_document.js at master · vercel/next.js · GitHub

import React from 'react';
import Document, {Html, Head, Main, NextScript} from 'next/document';
import {ServerStyleSheets as MaterialUIStyleSheets} from '@material-ui/core/styles';
import {ServerStyleSheet as StyledComponentsStyleSheets} from "styled-components";

export default class MyDocument extends Document {
    render() {
        return (
            <Html lang="ja">
                <Head/>
                <body>
                <Main/>
                <NextScript/>
                </body>
            </Html>
        );
    }
}

MyDocument.getInitialProps = async (ctx) => {
    const materialUISheets = new MaterialUIStyleSheets()
    const styledComponentsSheets = new StyledComponentsStyleSheets()
    const originalRenderPage = ctx.renderPage

    try {
        ctx.renderPage = () =>
            originalRenderPage({
                enhanceApp: (App) => (props) => styledComponentsSheets.collectStyles(
                    materialUISheets.collect(<App {...props} />)
                ),
            })

        const initialProps = await Document.getInitialProps(ctx);

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

material-ui の Button を styled-component でカスタマイズしてみる

pages/sample.js みたいなのを作って、カスタマイズしてみる。

styled() に material-ui の Component を渡してあげれば style を上書きできる。

import React from 'react';
import styled from 'styled-components';
import Button from '@material-ui/core/Button';

const StyledButton = styled(Button)`
  background-color: red;
`;

const Sample = () => {
    return (
        <div>
            <StyledButton>Customized</StyledButton>
        </div>
    )
}

export default Sample

参考