MUI (Material-UI) v5でmakeStylesが非推奨になったのでstyledを使ってみる

Material UI v5が2021年9月16日にリリースされ、makeStylesが非推奨になってしまいライブラリをアップデートするためにmakeStylesからstyledに置き換え対応を行いました。

これからv4からv5への移行をこれから行う人のためになればと思いサンプルコードを使って記事にしました。

- Material-UI v4 の記法サンプル
- 実際に行った作業
    - MUI v5のライブラリを追加
    - import先の変更
    - styledを使ったコンポーネントへのスタイリングの適用
- 完成品
- 置き換えをした感想
- 最後に

Material-UI v4 の記法サンプル
---
makeStylesを使用して自作hooksを作成して、各コンポーネントにclassNameをあてているDialogになります。

```React
import { makeStyles, createStyles } from '@material-ui/core/styles';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import Dialog from '@material-ui/core/Dialog';

const useStyles = makeStyles((theme) => createStyles({
  title: {
    color: theme.palette.primary.main,
    borderBottom: `1px solid ${theme.palette.grey[300]}`
  },
  content: {
    color: theme.palette.grey[700]
  }
}));

export const SampleDialog: React.FC = (props) => {
  const classes = useStyles();
  const { handleClose, open, title, content } = props;
  return (
    <Dialog onClose={handleClose} open={open}>
      <DialogTitle className={classes.title}>
        {title}
      </DialogTitle>
      <DialogContent className={classes.content}>
        {content}
      </DialogContent>
    </Dialog>
  );
};
```
実際に行った作業
===

##### MUI v5のライブラリを追加

```
yarn add @mui/material @emotion/react @emotion/styled
```
ライブラリが`@mui/~`になっているのでアップデートではMUI v5にならないので気を付けてください。
別ライブラリになるのでv4とv5の共存ができるため、のんびり移行作業ができるのは地味にありがたいですね

##### import先の変更
```jsx
import { styled } from '@mui/material/styles';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import Dialog from '@mui/material/Dialog';
```
`@material-ui/core~`から`@mui/material/~`へimportの向き先を変更
また`@mui/material/styles`から今回使用するstyledのimportします。
`@mui/system`からもstyledをimportできますが、こちらをimportしてしまうとテーマを参照できなくなってしまうので注意です。
詳しくは[公式サイト MUI styled](https://mui.com/system/styled/#main-content)に説明があるのでこちらをご覧ください。
##### styledを使ったコンポーネントへのスタイリングの適用
styledという名前ですので、styled-componentsのように記述します。

```jsx
const SampleDialogTitle = styled(DialogTitle)(({ theme }) => ({
  color: theme.palette.primary.main,
  borderBottom: `1px solid ${theme.palette.grey[300]}`
}));

const SampleDialogContent = styled(DialogContent)(({ theme }) => ({
  color: theme.palette.grey[700]
}));
```
完成品
===
コンポーネントからclassNameがなくなってすっきりしました。

```jsx
import { styled } from '@mui/material/styles';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import Dialog from '@mui/material/Dialog';

const SampleDialogTitle = styled(DialogTitle)(({ theme }) => ({
  color: theme.palette.primary.main,
  borderBottom: `1px solid ${theme.palette.grey[300]}`
}));

const SampleDialogContent = styled(DialogContent)(({ theme }) => ({
  color: theme.palette.grey[700]
}));

export const SampleDialog: React.FC = (props) => {
  const { handleClose, open, title, content } = props;
  return (
    <Dialog onClose={handleClose} open={open}>
      <SampleDialogTitle>
        {title}
      </SampleDialogTitle>
      <SampleDialogContent>
        {content}
      </SampleDialogContent>
    </Dialog>
  );
};
```
置き換えをした感想
===
いろんな画面で使う小さめのコンポーネントだと置き換えが簡単にできました。
そこそこ大きいコンポーネントだとdivタグにそれぞれclassNameでCSSを適用している箇所があり、そういったコンポーネントに対して置き換えが非常に大変でした。
今回、紹介していませんでしたがMUI v5にはstyledとは別に各コンポーネントにsxというpropsがありそちらも合わせて使えば上記の問題は何とかなるのかなといった感じです。

最後に
===
styledはMUIで提供されているコンポーネント以外にもdivやspanといったタグにもスタリングして使用することができます。
今までSassを使ってこの要素の子要素にまとめてCSSをあてるということをやることが多かったのですが、styledを使えばこのdivはCSSが適用されていることが一目でわかるのも便利です。

```React
import * as React from 'react';
import { makeStyles, createStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';

const useStyles = makeStyles((theme) => createStyles({
  root: {
    '& > div': {
      color: theme.palette.primary.main
    }
  }
}));
export const SampleDialog: React.FC = () => {
  const classes = useStyles();
  return (
    <Paper className={classes.root}>
      <div>a</div>
    </Paper>
  );
};

```
このようにuseStylesの中身を見ないとただのdivにしか見えず実装者以外にはわかりずらいdivタグも一目でただのdivタグではないことがわかります。

```React
import * as React from 'react';
import { Paper } from '@mui/material';
import { styled } from '@mui/material/styles';

const DivPrimary = styled('div')(({ theme }) => ({
  color: theme.palette.primary.main
}));

export const SampleDialog: React.FC = () => {
  return (
    <Paper>
      <DivPrimary>a</DivPrimary>
    </Paper>
  );
};

```