[React]Material UIのテーブルを使ったときに、コードが汚くなったので調整した。

Material UIは動くサンプルをカタログ的に選んですぐ使えますが、
一方で、理解できていないまま使ってしまうということにもなりがちです。
私は特にテーブルコンポーネントを扱うときに、ちょっと雑に扱っていた気がします。

コンポーネントによってはサンプルが結構行数が長くなってしまうのが原因だと思ってます。

[Material-UI | Table](https://material-ui.com/components/tables/#table)

Custom pagination optionsをベースに使っていたのですが、175行と少しコード量があります。
また、Sorting $ selecting は382行あります。
微調整をして、多少汚かったり理解していないコードがあっても、
コンポーネントに閉じてしまえばどうにかなるのですが、
変更は加えづらいので、よくないですよね。

カタログ的に並んでいてソースもコピーできるのですが、
- 最小限の構成を理解する
- その後必要な要素を付け足す
- スタイルをStyled component風に書く
の方針で進めていったほうが良さそうです。

それでは見ていきましょう。

## Basic tableを理解して、コンポーネントとして使えるようにする。

こういうのは一番シンプルなものから見ていくのが理解がしやすいですよね。
とりあえず公式のBasic tableから見ていきます。
こんな感じです。

```tsx
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

const useStyles = makeStyles({
  table: {
    minWidth: 650,
  },
});

function createData(name: string, calories: number, fat: number, carbs: number, protein: number) {
  return { name, calories, fat, carbs, protein };
}

const rows = [
  createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
  createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
  createData('Eclair', 262, 16.0, 24, 6.0),
  createData('Cupcake', 305, 3.7, 67, 4.3),
  createData('Gingerbread', 356, 16.0, 49, 3.9),
];

export default function BasicTable() {
  const classes = useStyles();

  return (
    <TableContainer component={Paper}>
      <Table className={classes.table} aria-label="simple table">
        <TableHead>
          <TableRow>
            <TableCell>Dessert (100g serving)</TableCell>
            <TableCell align="right">Calories</TableCell>
            <TableCell align="right">Fat&nbsp;(g)</TableCell>
            <TableCell align="right">Carbs&nbsp;(g)</TableCell>
            <TableCell align="right">Protein&nbsp;(g)</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map((row) => (
            <TableRow key={row.name}>
              <TableCell component="th" scope="row">
                {row.name}
              </TableCell>
              <TableCell align="right">{row.calories}</TableCell>
              <TableCell align="right">{row.fat}</TableCell>
              <TableCell align="right">{row.carbs}</TableCell>
              <TableCell align="right">{row.protein}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}
```

createData関数でデータを使っていますが、
上記のようになっていますが、親コンポーネントで使うとしたらこんな感じにしたくないでしょうか。

```tsx

<BasicTable 
  headers={["headerA", "headerB", "headerC", "headerD",]}
  datas={
    [
      {A: "dataA", B: "dataB", C: "dataC", D: "dataD", E: "dataE"},
      {A: "dataA", B: "dataB", C: "dataC", D: "dataD", E: "dataE"},
      {A: "dataA", B: "dataB", C: "dataC", D: "dataD", E: "dataE"},
    ]
  }
/>
```

その場合、createDataやrowsなどは必要なくなります。
また、TableCellの記述もmapを使った形式に変わっていきます。

```tsx
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

const useStyles = makeStyles({
  table: {
    minWidth: 650,
  },
});

export default function BasicTable({headers, datas}) {
  const classes = useStyles();

  return (
    <TableContainer component={Paper}>
      <Table className={classes.table} aria-label="simple table">
        <TableHead>
          <TableRow>
            {headers.map((header) => {
              <TableCell align="right" key{header}>header</TableCell>
            })}
          </TableRow>
        </TableHead>
        <TableBody>
          {datas.map((data, i) => (
            <TableRow key={'tableData' + i}>
              <TableCell align="right">{data.A}</TableCell>
              <TableCell align="right">{data.B}</TableCell>
              <TableCell align="right">{data.C}</TableCell>
              <TableCell align="right">{data.D}</TableCell>
              <TableCell align="right">{data.E}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}
```

こうすると、かなりスッキリして見通しよくなってきましたね。

makeStylesとuseStylesでTableをスタイリングしていることがわかります。
Table、TableHead、TableBody、TableRow、TableCellも大体わかると思います。
<TableContainer component={Paper}>だけちょっと気になりますよね。

componentは、HTMLタグ名(例: 'div')やコンポーネント名(例: Paper)を指定できます。
この場合、Paperコンポーネントをスタイリングを利用しています。
これで、Simple Componentが理解できました。

これに、付け加えていく形で進めていくと良さそうです。

## カスタムスタイルをStyled components風に分離する。

上記のコード例だと、スタイルを調整するmakeStylesの行数も5行と少ないです。ただ、実装したい内容によってはどんどん結構長くなってしまいます。

また、useStylesとかmakeStylesとかcreateStylesとか使いたくないなと思っていました。
classes.classNameのような形で設定しなければいけないのもちょっと嫌だなと思っていました。
どうにか回避する方法はないかなと思ったらありました。

[Material-UI | styles](https://material-ui.com/styles/basics/)

Styled components API

```tsx
import React from 'react';
import { styled } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const MyButton = styled(Button)({
  background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
  border: 0,
  borderRadius: 3,
  boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
  color: 'white',
  height: 48,
  padding: '0 30px',
});

export default function StyledComponents() {
  return <MyButton>Styled Components</MyButton>;
}
```

上記のようにStyled component風に書くことができます。


(2022年3月追記)
@mui/styles (LEGACY)となっていました。

> ⚠️ @mui/styles is the legacy styling solution for MUI. It depends on JSS as a styling solution, which is not used in the @mui/material anymore, deprecated in v5. If you don't want to have both emotion & JSS in your bundle, please refer to the @mui/system documentation which is the recommended alternative.

[MUI System](https://mui.com/system/basics/)に書いている感じですと、下記のように書くといけそうですね。
```tsx
import { styled } from '@mui/material/styles';

const Div = styled('div')`
  border: 0,
`;
```