Material-UIを使ってダイアログを表示するには？

Material-UIを使ってダイアログを表示するには一筋縄ではいかずパラメータを渡す必要があります。
なので今回は「**Material-UIを使ってダイアログを表示する方法**」を紹介します。

![ダイアログ表示.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621361/7a15da35-64d8-a1ad-3bfb-3e78bd470890.gif)

この機能は3つのファイルで構成されています。

1. 一覧画面(index.jsx)
2. アイテムコンポーネント(item.jsx)
3. ダイアログコンポーネント(dialog.jsx)

## 1.一覧画面
![WS000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621361/f49b934f-15d9-d76d-734b-863707bc1dfd.jpeg)


```index.jsx
import React from 'react';
import Box from '@material-ui/core/Box';
import Item from "@comp/item";
import Grid from '@material-ui/core/Grid';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles((theme) => ({
  gridItem: {
    marginTop: theme.spacing(2),
  },
}));

// 表示するアイテムのリスト
const bookList = [
  {
    id: 1,
    title: "ファスト＆スロー",
    page: 100,
    image: "http://books.google.com/books/content?id=tNDza_Pb0UMC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api"
  },
  {
    id: 2,
    title: "ファストフードの恐ろしい話",
    page: 200,
    image: "http://books.google.com/books/content?id=ghgzDwAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api"
  },
  {
    id: 3,
    title: "英語でおもてなし・ファストフード食べ歩き",
    page: 300,
    image: "http://books.google.com/books/content?id=HC-gCAAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api"
  },
]

export default function Index(props) {
  const classes = useStyles();
  const compProps = {
    gridItem: {
      item         : true,
      space        : 5,
      xs           : 12,
      md           : 6,
      lg           : 3,
      className    : classes.gridItem
    }
  }

  return (
    <>
      <Box mx={10} mt={4}>
        <Box display="flex" alignItems="center">
          <h2>{props.title}</h2>
        </Box>
        <Grid container spacing={1}>
          {bookList.map(item =>
            <Grid {...compProps.gridItem} key={item.id}>
              <Item 
                bookParam={item}
                />
            </Grid>
          )}
        </Grid>
      </Box>
    </>
  );
}


```

**一覧画面(`index.jsx`)では定義したリストを順番に並べて表示**しています。

まずは、表示するリストのデータを定義しています。通常はAPIやDBから取得したりしますが、今回は見本なので直接定義しています。

そして、定義したリストデータをループで回して各アイテムを**`BookCard`というコンポーネントで表示**しています。各データは`bookParam`という名前で`BookCard`コンポーネントに渡しています。

## 2.アイテム

![WS000001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621361/7f287b7f-8ed5-8f3a-8e8f-4154ee9d13b9.jpeg)

```item.jsx
import React, {useState} from 'react';
import Dialog  from "@comp/dialog";
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
import Link from '@material-ui/core/Link';

const item = (props) => {

  /** 画面パラメータ */
  const [dialogOpenF, setDialogOpenF] = useState(false);

  /**
   * コンポーネントに渡す引数
   */
  const compProps = {
    bookShowDialog: {
      open : dialogOpenF,                     //ダイアログの表示プローアティ
      bookParam: props.bookParam,
      onClose: () => setDialogOpenF(false),   //ダイアログ非表示処理
    },
    showLink: {
      href: "#",
      onClick: () => setDialogOpenF(true)     //ダイアログ表示処理
    }
  }

  return (
    <Box>
      {/* 画像の表示 */}
      <Link {...compProps.showLink}>
        <img src={props.bookParam.image}/>
      </Link>

      {/* タイトルの表示 */}
      <Typography>
        <Link {...compProps.showLink}>
        {props.bookParam.title}
        </Link>
      </Typography>

      {/* ページ数の表示 */}
      <Typography>{props.bookParam.page}ページ</Typography>
      
      {/* ダイアログの表示 */}
      <Dialog {...compProps.bookShowDialog} />
    </Box>
  );
}

export default item;
```

**各アイテム(`item.jsx`)では呼び出し元から渡されたデータの表示とダイアログの表示・非表示の処理を行っています**。

引き渡されたパラメータは`props.bookParam`に格納されているため画像URL（`image`）、タイトル(`title`)、ページ数(`page`)をそのまま出力に利用しています。

そして、最後の`Dialog`コンポーネントに各アイテムの情報を渡しています。

### 2-1.ダイアログの表示・非表示

**ダイアログ表示・非表示用のパラメータ`dialogOpenF`を用意**しています。このパラメータをtrue・falseに更新することでダイアログの表示・非表示に切り替えているわけです。

後は画像とタイトルがクリックされたときに`dialogOpenF`を更新するメソッド`setDialogOpenF`を使ってtrueに変更しています。これにより`open`プロパティーが更新されダイアログが表示されます。

そして、ダイアログが閉じる処理を行ったときに**`setDialogOpenF`でfalseを指定してダイアログを非表示に更新**しています。

## 3.ダイアログ

![WS000002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621361/e36c5eeb-faa3-fe68-f6a6-18cb17b53a2e.jpeg)


```dialog.jsx
import React from 'react';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import PropTypes from 'prop-types';
import Typography from '@material-ui/core/Typography';

const dialog = (props) => {

  const compProps = {
    dialog: {
      open: props.open,           //ダイアログの表示・非表示プロパティ
      onClose: props.onClose,     //ダイアログが閉じられた時の処理
      scroll:'paper',
    },
    dialogContent: {
      dividers: true
    },
    dialogContentText: {
      tabIndex: -1
    },
    closeButton: {
      onClick: props.onClose,     //閉じるボタンが押されたときの処理
      color: "primary"
    },
  }

  return (
      <Dialog {...compProps.dialog}>
        {/* タイトル */}
        <DialogTitle>{props.bookParam.title}</DialogTitle>
        
        {/* 画像とページ数 */}
        <DialogContent {...compProps.dialogContent}>
          <img src={props.bookParam.image} />
          <DialogContentText {...compProps.dialogContentText}>
            <Typography>{props.bookParam.page}ページ</Typography>
          </DialogContentText>
        </DialogContent>

        {/* 閉じるボタン */}
        <DialogActions>
          <Button {...compProps.closeButton}>
            閉じる
          </Button>
        </DialogActions>
      </Dialog>
  );
}

dialog.propTypes = {
    open: PropTypes.bool,       //表示フラグ
    onClose: PropTypes.func,    //閉じる処理
  }
  
  export default dialog;

```

最後に**ダイアログに呼び出し元から渡された情報を出力**します。

`DialogTitle`にはアイテムのタイトル。`DialogContent`にはアイテムの画像とページ数を表示。そして、ダイアログを閉じる処理を行う「閉じるボタン」を定義します。

閉じるボタンが押されたときは呼び出し元から引き渡された`props.onClose`を利用します。これにより、呼び出し元からダイアログを非表示にします。

また、`propTypes`で呼び出し元からのパラメータの型をチェックしまています。`open`はダイアログの表示・非表示でboolean型。`onClose`は閉じる処理でfunc型。これにより異常な値が渡ってこれば警告が表示されるようになっているのです。