OKボタンや、YES / NO のボタンでユーザーに確認を促すメッセージダイアログを出すシーンは多くあり、その度に個別にダイアログを実装するのは無駄である。
そこで、汎用的に使えるダイアログコンポーネントを作ってみた。
スポンサーリンク
完成イメージ
作成するコンポーネントの完成イメージは次のとおり。よくあるメッセージダイアログで、使い方の説明は不要であろう。
今回は、OKまたは、YES / NOの2種類のボタンを表示できるように、プロパティで切り替えられるようにする。
スポンサーリンク
実装
まずは、ダイアログ側のソースである。
import {
  Box,
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle
} from '@mui/material';
import PropTypes from 'prop-types';
import React, { useEffect, useState } from 'react';
function CommonDialog(props: any) {
  // プロパティの受け取り
  const {
    title,
    message,
    onAccept,
    onClose,
    open,
    buttonType
  } = props;
  
  const [dialogOpen, setDialogOpen] = useState(false);
  // 承諾(OK または YES ボタンをクリック)した時
  const handleAccept = () => {
    handleClose();
    onAccept();
  };
  // ダイアログクローズ
  const handleClose = () => {
    setDialogOpen(false);
    onClose();
  };
  // openの値が変化した時
  useEffect(() => setDialogOpen(open), [open]);
  return (
    <Dialog
      open={dialogOpen}>
      <DialogTitle>
        <span>{title}</span>
      </DialogTitle>
      <DialogContent >
        <Box>
          {message}
        </Box>
      </DialogContent>
      <DialogActions>
        {buttonType == ButtonType.OkOnly &&
          <Button onClick={handleAccept}>OK</Button>
        }
        {buttonType == ButtonType.YesNo &&
          <>
            <Button onClick={handleAccept}>はい</Button>
            <Button onClick={handleClose}>いいえ</Button>
          </>
        }
      </DialogActions>
    </Dialog>
  );
}
// ボタン種別
export enum ButtonType {
  OkOnly = "OkOnly",
  YesNo = "YesNo",
}
// プロパティ
CommonDialog.propTypes = {
  title: PropTypes.string.isRequired,
  message: PropTypes.string.isRequired,
  onAccept: PropTypes.func.isRequired,
  onClose: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
  buttonType: PropTypes.oneOf([ButtonType.OkOnly, ButtonType.YesNo]).isRequired
};
export default CommonDialog;
次にダイアログを呼び出す側のコンポーネントを実装する。
import Button from '@mui/material/Button';
import React, { useState } from 'react';
import CommonDialog, { ButtonType } from './dialog/CommonDialog';
function Sample() {
  // ダイアログ用のstate
  const [digOpen, setDigOpen] = useState(false);
  return (
    <div>
      <CommonDialog
        title="タイトル"
        message="メッセージ本文です。"
        buttonType={ButtonType.OkOnly}
        open={digOpen}
        onAccept={() => console.log("onAccept")}
        onClose={() => setDigOpen(false)}
      />
      <Button onClick={() => setDigOpen(true)}>
        OPEN
      </Button>
    </div>
  );
}
export default Sample;
スポンサーリンク
実装2(スマホ時はフルスクリーンで表示)
スマホなどの、画面サイズが小さいデバイスの場合、フルスクリーンでダイアログを表示するように改造したソースは以下である。
import { 
  Box, 
  Button, 
  Dialog, 
  DialogActions, 
  DialogContent, 
  DialogTitle, 
  useMediaQuery } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import PropTypes from 'prop-types';
import React, { useEffect, useState } from 'react';
function CommonDialog(props: any) {
  // プロパティの受け取り
  const {
    title,
    message,
    onAccept,
    onClose,
    open,
    buttonType
  } = props;
  const theme = useTheme();
  const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
  const [dialogOpen, setDialogOpen] = useState(false);
  // 承諾(OK または YES ボタンをクリック)した時
  const handleAccept = () => {
    handleClose();
    onAccept();
  };
  // ダイアログクローズ
  const handleClose = () => {
    setDialogOpen(false);
    onClose();
  };
  // openの値が変化した時
  useEffect(() => setDialogOpen(open), [open]);
  return (
    <Dialog
      open={dialogOpen}
      maxWidth="sm"
      fullScreen={fullScreen}>
      <DialogTitle>
        <span>{title}</span>
      </DialogTitle>
      <DialogContent >
        <Box>
          {message}
        </Box>
      </DialogContent>
      <DialogActions>
        {buttonType == ButtonType.OkOnly &&
          <Button variant="contained" onClick={handleAccept}>OK</Button>
        }
        {buttonType == ButtonType.YesNo &&
          <>
            <Button variant="contained" onClick={handleAccept}>はい</Button>
            <Button color="secondary" variant="outlined" onClick={handleClose}>いいえ</Button>
          </>
        }
      </DialogActions>
    </Dialog>
  );
}
// ボタン種別
export enum ButtonType {
  OkOnly = "OkOnly",
  YesNo = "YesNo",
}
// プロパティ
CommonDialog.propTypes = {
  title: PropTypes.string.isRequired,
  message: PropTypes.string.isRequired,
  onAccept: PropTypes.func.isRequired,
  onClose: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
  buttonType: PropTypes.oneOf([ButtonType.OkOnly, ButtonType.YesNo]).isRequired
};
export default CommonDialog;
上のコードのポインタは、useMediaQuery で画面の横幅が 500px を下回った場合、Dialogコンポーネントの fullScreen プロパティに true を設定している部分である。

0 件のコメント:
コメントを投稿