【React】react-material-uiでTableの行と列を固定する

## 概要
UIのフレームワークで代表的なものの一つが`Material UI`で、React用のライブラリも用意されています。[こちら](https://mui.com/)のページにある通り、色々なコンポーネントが用意されているのですが、今回はTableのコンポーネントを使用してみました。
Tableのコンポーネントを使用する際に、行や列を固定したい時があると思いますが、その際の実装方法を今回紹介します。なお、今回使用したMaterial UIのバージョンは`5.6.0`になります。

## 実装方針
* ヘッダー行の固定ですが、Tableのドキュメント[sticky-header](https://mui.com/material-ui/react-table/#sticky-header)にある通り、Tableのコンポーネントに`stickyHeader`を設定します。
* 固定したい列がある場合は、[MUI Table Sticky Column Demo](https://codesandbox.io/s/mui-table-sticky-column-demo-7h7eq?file=/demo.tsx:482-490)のサンプル実装にある通り、TableCellのコンポーネントにCSSで`position: "sticky"`を設定します。また、列幅を固定したいので、TableのコンポーネントにてCSSで`tableLayout: "fixed"`を設定します。
横にスライドする時に要素がかぶる状態になるので`background`や`z-index`も、合わせて必要に応じて設定しましょう。

## 実装サンプル
実現するテーブルのイメージは以下になります。
ヘッダーのタイトル行および、列は`日時`と`地点名`を固定します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/dafea563-6535-6ceb-f3ef-74bf19030030.png" width="400px"/>

実装は以下の通りになります。

```react
import Image from "next/image";

import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";

export default function SampleComponent(prop) {

  function getStickyCellStyle(width, zIndex, left) {
    return {
      position: "sticky",
      left: left,
      background: "white",
      width: width,
      zIndex: zIndex,
    };
  }

  function renderWeatherInfo(weatherInfo) {
    return (
      <>
        <TableRow>
          <TableCell style={getStickyCellStyle(90, 90, 0)}>
            {getDateDisplayFromUnixTime(weatherInfo.getUnixtime())}
          </TableCell>
          <TableCell style={getStickyCellStyle(100, 90, 122)}>
            {weatherInfo.getPointname()}
          </TableCell>
          <TableCell>
            <Image
              src={weatherInfo.getWeatherImage()}
              width={40}
              height={40}
            />
          </TableCell>
          <TableCell>
            体感気温:{weatherInfo.getTempfeelslike()}°C
            <br />
            最低気温:{weatherInfo.getTempmin()}°C
            <br />
            最高気温:{weatherInfo.getTempmax()}°C
          </TableCell>
          <TableCell>
            雲量:{weatherInfo.getClouds()}%
            <br />
            降水量:{weatherInfo.getRainfall() ? weatherInfo.getRainfall() : 0}mm/3h
            <br />
          </TableCell>
          <TableCell>{weatherInfo.getHumidity()}%</TableCell>
          <TableCell>{weatherInfo.getWindspeed()}m/秒</TableCell>
          <TableCell>{weatherInfo.getPressure()}hpa</TableCell>
        </TableRow>
      </>
    );
  }

  return (
    <Paper
      sx={{
        width: 400,
      }}
    >
      <TableContainer sx={{ height: "80vh", maxWidth: 400 }}>
        <Table
          stickyHeader
          style={{
            tableLayout: "fixed",
          }}
        >
          <TableHead>
            <TableRow>
              <TableCell style={getStickyCellStyle(90, 100, 0)}>日時</TableCell>
              <TableCell style={getStickyCellStyle(100, 100, 122)}>
                地点名
              </TableCell>
              <TableCell style={{ width: 40 }}>天気</TableCell>
              <TableCell style={{ width: 120 }}>気温</TableCell>
              <TableCell style={{ width: 110 }}>雲・降水量</TableCell>
              <TableCell style={{ width: 60 }}>湿度</TableCell>
              <TableCell style={{ width: 60 }}>風速</TableCell>
              <TableCell style={{ width: 80 }}>気圧</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {prop.weatherList.map((weather) => {
              return renderWeatherInfo(weather);
            })}
          </TableBody>
        </Table>
      </TableContainer>
    </Paper>
  );
}


```