CSSをMATERIAL-UIのmakeStylesで書き換える

Reactの学習をしていて`CSS in JS`なるものに出会ったので、
基本的な内容ながらまとめておきたいと思います。

普通のCSS(CSSファイル形式で書いたCSS)をMATERIAL-UIのmakeStylesで書き換える、ちょっとした手がかりのつもりです。

## 知れること・知れないこと

**知れること**

- CSSファイルの形式で書かれたスタイルをMATERIAL-UIのmakeStylesで書き換える方法

**知れないこと**

- MATERIAL-UI以外の実装方法
- `CSS in JS`の是非

## CSS in JS って？
字のごとく`JSの中でCSSを書く`スタイルの一つの書き方(おそらく総称)。
フロントエンドフレームワークで出てくる`コンポーネント`の概念とともに検討され始めた書き方らしいです。
ざっくり言うと、「コンポーネント単位で実装するんだったら、CSSもコンポーネント単位で書いた方がよくない？（CSSをわざわざファイル分けするのは管理上適切ではないのでは？）」と言ったことらしい。

参考
[styled-componentsで変わるReactコンポーネントのスタイリング](https://www.wakuwakubank.com/posts/717-react-styled-components/)

## 元々のCSSの記述
以下のような`タグ`のスタイルを今回対象にしてみます。
<img width="300" height="200" alt="css2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277737/f8b3d705-267d-7709-cd79-93f95c53e211.gif">

※こちらのCSSファイルの内容自体は以下のサイトのものほぼほぼそのままです。
[CSSで実装するタグクラウドのサンプル](https://www.nxworld.net/tips/css-tag-cloud.html)

```tag.css
.taggroup ul {
    margin: 0;
    padding: 0;
    list-style: none;
}
.taggroup ul li {
    display: inline-block;
    margin: 0 .3em .3em 0;
    padding: 0;
}
.taggroup ul li a {
    display: inline-block;
    max-width: 100px;
    height: 28px;
    line-height: 28px;
    padding: 0 1em;
    background-color: #fff;
    border: 1px solid #aaa;
    border-radius: 3px;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    color: #333;
    font-size: 13px;
    text-decoration: none;
    transition: .2s;
}
.taggroup ul li a:hover {
    background-color: #555;
    color: #fff;
}
```

CSSファイルで書いた場合は、
以下のようにファイルを読み込んで`className`にクラス名を付与して利用します。

```TagCss.js
import React from 'react';
import Container from '@material-ui/core/Container';
import Grid from '@material-ui/core/Grid';
import Box from '@material-ui/core/Box';
import "./Tag.css";

const TagCss = () => {
    return (
        <>
            <Container>
                <Grid container>
                    <Grid item xs={12} sm={12} md={12} lg={12}>
                        <Box textAlign="center" mt={5}>
                            <Box mb={1}>CSS</Box>
                            <div className="taggroupcss">
                                <ul>
                                    <li><a href="#">JavaScript</a></li>
                                    <li><a href="#">React</a></li>
                                </ul>
                            </div>
                        </Box>
                    </Grid>
                </Grid>
            </Container>
        </>
    )
}

export default TagCss;
```


`TagCss`の表示例をもう一度
<img width="300" height="200" alt="css2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277737/f8b3d705-267d-7709-cd79-93f95c53e211.gif">


## MATERIAL-UIのmakeStylesで書き換えた例

これをMATERIAL-UIのmakeStylesで書き換えると、一つのjsファイルにまとめて記載できるという寸法です。

```Tag.js
import React from 'react';
import Container from '@material-ui/core/Container';
import Grid from '@material-ui/core/Grid';
import Box from '@material-ui/core/Box';
import { makeStyles } from '@material-ui/core';

const Tag = () => {
    const classes = tagStyle();
    return (
        <>
            <Container>
                <Grid container>
                    <Grid item xs={12} sm={12} md={12} lg={12}>
                        <Box textAlign="center" mt={5}>
                            <Box mb={1}>makeStyles(CSS in JS)</Box>
                            <div className={classes.taggroup}>
                                <ul>
                                    <li><a href="#">JavaScript</a></li>
                                    <li><a href="#">React</a></li>
                                </ul>
                            </div>
                        </Box>
                    </Grid>
                </Grid>
            </Container>
        </>
    )
}

const tagStyle = makeStyles(() => ({
    taggroup: {
        "& ul": {
            margin: "0",
            padding: "0",
            listStyle: "none",
            "& li": {
                display: "inline-block",
                margin: "0 .3em .3em 0",
                padding: "0",
                "& a": {
                    display: "inline-block",
                    maxWidth: "100px",
                    height: "28px",
                    lineHeight: "28px",
                    padding: "0 1em",
                    backgroundColor: "#fff",
                    border: "1px solid #aaa",
                    borderRadius: "3px",
                    whitespace: "nowrap",
                    textOverflow: "ellipsis",
                    overflow: "hidden",
                    color: "#333",
                    fontSize: "13px",
                    textDecoration: "none",
                    transition: ".2s",
                    "&:hover": {
                        backgroundColor: "#555",
                        color: "#fff"
                    }
                }
            }
        }
    }
}));


export default Tag;

```


`Tag`の表示例
（書き換えただけなんだから`TagCss`と同じ表示のされ方をしないとおかしいですね）
<img width="300" height="200" alt="makestyle.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277737/b8fb73ca-d1ae-6375-ecdb-b5400380b040.gif">

## 書き換えのポイント

makeStyleの基本的な使い方は以下が参考になります。
[React: Material-UI 4.0のコンポーネントへのCSS設定はwithStyles()からmakeStyles()に](https://qiita.com/gumiTECH/items/9e0f3172b8f85e93cbbe)
[公式](https://material-ui.com/ja/styles/api/)

一つ目のサイトから書式の説明を拝借すると以下のような感じです。

```js
const フック関数 = makeStyles((theme) => ({
  クラス: {
    プロパティ: 文字列の設定値,
    // 他のプロパティの定め
  },
  // 他のクラス
}));
```
（今回前述した例は、引数の`theme`なしバージョンです）

### ポイント : プロパティをキャメルケースに変更して書く

例えば

```tag.css
.taggroup ul {
    margin: 0;
    padding: 0;
    list-style: none;
}
```
の`list-style`は、

```tag.js
const tagStyle = makeStyles(() => ({
    taggroup: {
        "& ul": {
            margin: "0",
            padding: "0",
            listStyle: "none",
~~以下省略~~
```
といった風に`listStyle`に変更します。
参考 : [material-uiの見た目を調整する3つの方法](https://qiita.com/junara/items/b8251bcb75760467aca4)などなど。

また、実は、以下のようにプロパティを文字列として扱っても表示は同じになります。

```tag.js
const tagStyle = makeStyles(() => ({
    taggroup: {
        "& ul": {
            margin: "0",
            padding: "0",
            "list-style": "none",
~~以下省略~~
```
最悪、元のCSSの中身を"だか'で囲みまくったら、書き換え可能ってことですね。（是非はともかく……）

〜〜〜
少し余談ですが、`ベンダプレフィックス`が必要なプロパティの場合は、試した限りは文字列として扱った書き換えしかできなさそうでした。（`ベンダプレフィックス`→`-webkit-`など）

```css
.exp {
    -webkit-transition: .2s;
}
```
なんてのがあったら

```js
const expStyle = makeStyles(() => ({
    exp: {
        "-webkit-transition": ".2s";
    }
}));
```
とします。

まあ、文字列で書き換える前に、本当に`ベンダプレフィックス`（`-webkit-`）が必要なのかどうかは見ておいた方がいいでしょうね。
参考 : [そのベンダープレフィックス、いつまでつけてるの？](https://qiita.com/amamamaou/items/42197e443134478befaf)

### ポイント : 絞り込みは&を使う！

```tag.css
.taggroup ul li {
    display: inline-block;
    margin: 0 .3em .3em 0;
    padding: 0;
}
```

上記のように、**taggroupクラスを使った要素の中のulの中のli**と、
スタイルを指定する範囲を絞り込んでいく場合。（割と分からなかった）

（答えはすでに書いてあるわけですが）入れ子構造にして文字列として&でつなげていけばOKです。
・上記書き換え分の抜粋

```tag.js
const tagStyle = makeStyles(() => ({
    taggroup: {
        "& ul": {
           ~~省略~~
            "& li": {
                display: "inline-block",
                margin: "0 .3em .3em 0",
                padding: "0",
           ~~省略~~
```
`a:hover`なんかも、このやり方で記述可能です。
・`a:hover`の部分の抜粋

```tag.js
const tagStyle = makeStyles(() => ({
    taggroup: {
                ~~省略~~
                "& a": {
                    ~~省略~~
                    "&:hover": {
                        backgroundColor: "#555",
                        color: "#fff"
                    }
                ~~省略~~
```

ちなみに、
SCSSやSASSでスタイルを書いている人にとっては、`&でつなげる`というのは割と自然な考え方のようです。

参考
[[SCSS]便利な&（アンパサンド）の使い方メモ](https://qiita.com/noqua/items/adc24c28c13e9b74d3ad)
[【Sass】親セレクタを参照する&や+の使い方](https://qiita.com/yoshida-hi/items/4caa37028080872cdc1a)

### その他
アニメーションの書き方にも、多少コツが必要そうです。

何度も出している参考記事
[React: Material-UI 4.0のコンポーネントへのCSS設定はwithStyles()からmakeStyles()に](https://qiita.com/gumiTECH/items/9e0f3172b8f85e93cbbe)
(こちらの記事ではひな形のアプリケーションのCSSをmakeStyleに書き換えたものが載っていて、アニメーションについても言及されています)

## おわりに
「いや、別に無理して書き換えなくてもCSSのままでもいいんじゃない？」　と言う話は実際あるようですが、「CSSで書いていたものが、`CSS in JS`だと全く検討もつかない！」というのは、ちょっと癪だったので、いろいろ調べてみました。
（書き換えることに集中したため詳しい`CSS in JS`の是非までは追求していないです:sweat_smile:）

`CSS in JS`のメリットの話（動的にスタイルを変更できるなど）といった発展的な話まではでできていませんが、最初に書いたように、この記事が`makeStyles`（その他）を使うときのちょっとした手がかりになってもらえたら嬉しいです!!

以上になります！