Material-uiがv5へアップデートされたので、Next.jsで対応する。

皆さんこんにちは。

Material-uiがv5へ大型なアップデートされましたね。

コンポーネント自体はCSSの扱いが変更されたくらいで大きな変更などはありませんが、パッケージ名が変わったので大きなプロジェクトで採用していると対応するのにかなり時間が掛かりそう。。。

また、CSSの扱い方が``emotion``と``styled-components``に合わせたらしいのでNext.jsやGatsby.jsなどのReactのフレームワークを利用している方はdocument、appファイルにいくつかの変更が加わります。

そこで、今回は、早速v5を体験したい方やv5のバージョンに対応したいという方に向けた記事となります。

コンポーネントの扱い方などは既に記事を出されている方も多いのですが、Next.jsでv5に対応する記事は少なかったため皆さんの助けになればなと思います。

# 注意事項

先程も申し上げたとおり、v5になってemotionとstyled-componentsが使用されるようになりました。

私自身、これらのCSSライブラリに触れたことがないため、今回はemotionで対応するだけの記事となりますのでご了承下さい。

時間があるときにstyled-componentsでの対応も追加していきます。

それでは早速説明していきます。

# パッケージのインストール

```terminal
// npm
npm i @mui/material @emotion/cache @emotion/react @emotion/server @emotion/styled

// yarn
yarn add @mui/material @emotion/cache @emotion/react @emotion/server @emotion/styled
```

# emotionのキャッシュ（？）用のファイルを作成

stylesディレクトリにemotionのキャッシュ用のファイルを作成。

```terminal
touch styles/createEmotionCache.ts
```

```styles/createEmotionCache.ts
import createCache from '@emotion/cache';

export default function createEmotionCache() {
  return createCache({ key: 'css' });
}
```

# _app.tsx

任意の場所に以下のプロバイダーを設置して下さい。

```_app.tsx
import { CacheProvider } from '@emotion/react';
import createEmotionCache from '@/styles/createEmotionCache';

const clientSideEmotionCache = createEmotionCache();

const Appr: React.FC = ({ children }) => {
  return (
    <CacheProvider value={clientSideEmotionCache}>
      // 省略
    </CacheProvider>
  );
};

export default App;
```

# _document.tsx

以下をコピペ

```_document.tsx
import { Children, ReactElement } from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import createEmotionCache from '../styles/createEmotionCache';
import createEmotionServer from '@emotion/server/create-instance';

class MyDocument extends Document {
  render(): JSX.Element {
    return (
      <Html lang="ja">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

MyDocument.getInitialProps = async (ctx) => {
  const originalRenderPage = ctx.renderPage;

  const cache = createEmotionCache();
  const { extractCriticalToChunks } = createEmotionServer(cache);

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App) =>
        function AppEmotionCache(props): ReactElement {
          return <App {...props} />;
        },
    });

  const initialProps = await Document.getInitialProps(ctx);

  const emotionStyles = extractCriticalToChunks(initialProps.html);
  const emotionStyleTags = emotionStyles.styles.map((style) => (
    <style
      data-emotion={`${style.key} ${style.ids.join(' ')}`}
      key={style.key}
      // eslint-disable-next-line react/no-danger
      dangerouslySetInnerHTML={{ __html: style.css }}
    />
  ));

  return {
    ...initialProps,
    // Styles fragment is rendered after the app and page rendering finish.
    styles: [...Children.toArray(initialProps.styles), ...emotionStyleTags],
  };
};
```

一応これでMateriuiのv5を使用することが出来ます。

若干付け焼き刃的な感じがしますが、そこは見逃していただけると幸いです。

もしかしたら、うまく動作しない場合もあるかもしれないのでコメントにて気軽にご質問下さい。

時間がるときにstyled-componentsの対応もします。

以上、「Material-uiがv5へアップデートされたので、Next.jsで対応する。」でした。

Thank you for reading

# 参考記事

[https://www.ansonlowzf.com/create-a-website-with-material-ui-v5-nextjs/](https://www.ansonlowzf.com/create-a-website-with-material-ui-v5-nextjs/)