[Material-UI] ループ処理で生成したボタンのうちどれがクリックされたのかをハンドラー側で分かるようにする

2021.07.21

こんにちは、CX事業本部 IoT事業部の若槻です。

ReactのUIフレームワークであるMaterial-UIで実装した画面で、ループ処理で生成したボタンのうちどれがクリックされたのかをハンドラー側で分かるようにしてみました。

環境

$ npm list --depth=0
...
├── @material-ui/core@4.12.2
├── react@17.0.2
├── typescript@4.2.4
...

コード

App.tsx

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";

const useStyles = makeStyles((theme) => ({
  typography: {
    marginTop: theme.spacing(20),
    marginBottom: theme.spacing(10),
  },
  grid: {
    margin: "auto",
  },
  button: {
    marginTop: "auto",
    marginBottom: theme.spacing(5),
    width: "250px",
    height: "200px",
    fontSize: "30px",
    margin: theme.spacing(1),
  },
}));

const questionText = "今日の会社説明会はどうでしたか?";
const choices = ["とても満足", "満足", "普通", "不満", "とても不満"];

//クリックハンドラー
const onClickHandler = (index: number) => {
  window.alert(index + 1);
};

const App: React.FC = () => {
  const classes = useStyles();

  return (
    <div>
      <Typography variant="h2" align="center" className={classes.typography}>
        <div>{questionText}</div>
      </Typography>
      <Grid container>
        {choices.map((choice, index) => (
          <Grid item className={classes.grid}>
            <Button
              variant="contained"
              color="primary"
              className={classes.button}
              onClick={() => onClickHandler(index)}
            >
              {index + 1 + ". " + choice}
            </Button>
          </Grid>
        ))}
      </Grid>
    </div>
  );
};

export default App;

map()メソッドを使用してボタン<Button>をループ処理により生成しています。map()では第2引数のindexが現在処理中の要素の配列内における添字を表します。そこでmap()indexをボタンのハンドラー関数に引数として渡すことにより、どのボタンがクリックされたのかがハンドラー側で分かるようにしています。

<Grid>はレスポンシブレイアウトグリッドを実装するためのMaterial-UIのComponentです。詳しくは前回の記事をご確認ください。

動作

1. とても満足をクリックした時。

4. 不満をクリックした時。

ちゃんとクリックしたボタンのindexがハンドラーに渡っていますね。

HTMLのボタンの場合

当たり前ですがHTMLのボタン要素の場合も同様のことが出来ます。

先程のコードで<Grid item>の内容を<button>に差し替えています。

const App: React.FC = () => {
  const classes = useStyles();

  return (
    <div>
      <Typography variant="h2" align="center" className={classes.typography}>
        <div>{questionText}</div>
      </Typography>
      <Grid container>
        {choices.map((choice, index) => (
          <Grid item className={classes.grid}>
            <button onClick={() => onClickHandler(index)}>
              {index + 1 + ". " + choice}
            </button>
          </Grid>
        ))}
      </Grid>
    </div>
  );
};

3. 普通をクリックしたら、クリックしたボタンのindexがちゃんとハンドラーに渡されています。

以上