【Material-UI】v4で追加された気になる新機能

[Material-UI]:https://material-ui.com/

先日、[Material-UI] の新バージョン4.0がリリースされました。
Material-UI は React で最も人気があるUIコンポーネントライブラリです。

早速、個人的に気になる機能を試してみました。



# 主な情報源

- [Material-UI v4 is out 🎉 - Material-UI](https://material-ui.com/blog/material-ui-v4-is-out/)
- [material-ui/CHANGELOG.md at master · mui-org/material-ui](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)



# 気になる新機能

- [レイアウトコンポーネント(Box/Container)が追加された](#レイアウトコンポーネントboxcontainerが追加された)
- [Hook APIが追加された](#hook-apiが追加された)
- [makeStylesで関数が使えるようになった](#makestylesで関数が使えるようになった)
- [Theme.spacingで関数が使えるようになった](#themespacingで関数が使えるようになった)
- [TextFieldのテーマ設定ができるようになった](#textfieldのテーマ設定ができるようになった)



## レイアウトコンポーネント(Box/Container)が追加された

レイアウト用に２つのコンポーネントが追加されました。



### Box

https://material-ui.com/components/box/

他のコンポーネントをラップしてスタイルを適用するためのコンポーネントです。
BoxコンポーネントはプロパティでCSSスタイルを指定できます。

```tsx:
function Component() {
    return (
        <Box m={2} p={1} color="palette.primary">
            <div></div>
        </Box>
    );
}
```

- プロパティの一覧 https://material-ui.com/system/api/
- paddingとmarginは省略して書ける
    - `padding`は`p`、`margin`は`m`
    - `padding-top`は`pt`
    - `padding-left`と`padding-right`は`px`
- `p={1}`は`1px`ではなく`theme.spacing(1)`の意味(theme.spacingについては後述)

v3まではレイアウト目的で`<div>`を使うことがありましたが、これからは`<Box>`に直接プロパティでスタイルを指定できるようになります。

```tsx:中央寄せ
function Component() {
    return (
        <Box textAlign="center">
            <Button>a</Button>
            <Button>b</Button>
            <Button>c</Button>
        </Box>
    );
}
```
```tsx:flex-box
function Component() {
    return (
        <Box display="flex" justifyContent="space-between">
            <Button>a</Button>
            <Button>b</Button>
            <Button>c</Button>
        </Box>
    );
}
```

### Container

https://material-ui.com/components/container/

コンテンツを中央寄せするためのコンポーネントです。

最近のWebページではコンテンツを中央寄せで表示するのが一般的なので、地味に便利なコンポーネントです。



## Hook APIが追加された

https://material-ui.com/styles/basics/#hook-api
https://material-ui.com/styles/advanced/#accessing-the-theme-in-a-component

v3まではコンポーネント内でテーマ、スタイルを使用したい場合、それぞれ`withTheme`、`withStyles`を使う必要がありました。
いわゆるHOCというやつです。

v4からは上記に加えて Hook API も使えるようになりました。


```tsx:テーマの使用
import {useTheme} from "@material-ui/core/styles";

function MyComponent() {
    const theme = useTheme();
    return <span color={theme.palette.primary.main}>primary color</span>
}
```
```tsx:スタイルの使用
import {makeStyles} from "@material-ui/core/styles";

const useStyles = makeStyles({
  myButton: {
    borderWidth: 4,
  },
});

const MyComponent = () => {
  const classes = useStyles();
  return (
    <Button className={classes.myButton}>a</Button>
  );
};
```

TypeScriptを使っているとHOCスタイルだと型指定が結構面倒なのですが、Hook API だと簡単に書けるようになります。
ただし`withStyles`に関してはコンポーネントを使用する側でスタイルを上書きする用途もあるので使い分けが必要になります。



## makeStylesで関数が使えるようになった

https://material-ui.com/styles/basics/#adapting-based-on-props

`makeStyles`ではスタイルの値を設定する関数を使用できます。

```tsx:
import {makeStyles, Theme} from "@material-ui/core/styles";

type Props = {
  color: string;
};

const useStyles = makeStyles<Theme, Props>({
  root: ({ color }) => ({
    backgroundColor: color
  })
});

function ColorButton(props: Props) {
  const classes = useStyles(props);
  return <Button className={classes.root}>{props.color}</Button>;
}
```


## Theme.spacingで関数が使えるようになった

https://material-ui.com/customization/spacing/

v3のテーマでは`spacing.unit`に基本となる数値を１つだけ指定して、使用する場所でこれを倍にして使うという方法でした。

```tsx:v3
const theme = createMuiTheme({
    spacing: {
        unit: 4
    }
});
```
v4からは`spacing`に関数を指定できるようになりました。

```tsx:v4
import { Spacing } from "@material-ui/core/styles/createSpacing";

const theme = createMuiTheme({
    spacing: (factor => 4 ** factor) as Spacing;
});

const Component = () => <box p={1}>padding 4px</box>;
const Component = () => <box p={2}>padding 16px</box>;
```



## TextFieldのテーマ設定ができるようになった

MUIのテーマでは各コンポーネントのデフォルトプロパティとスタイルを指定することができます。
しかしv3まではTextFieldだけはデフォルトを指定することができませんでした。

v4からはTextFieldもデフォルト指定できるようになりました。

```tsx:
const theme = createMuiTheme({
    defaults: {
        MuiTextField: {
            variant: "outlined",
        },
    },
});
```



# 最後に

ここに記載した内容はあくまで個人的に気になる機能のみです。
他の新機能や変更点は公式ドキュメントを参照してください。

また、v3からの移行ガイドは以下を参照してください。

[Migration From v3 to v4 - Material-UI](https://material-ui.com/guides/migration-v3/)