React で Modal Dialog の終了を promise で待って後続の処理を実行する一番手っ取り早そうな方法

19736 ワード

React + Typescript + MUIv5 で開発環境を作成しています。
今回は Modal Dialog の終了を待って後続の処理を実行する方法で、一番簡単そうな方法です。

やりたいこと

求めていることは、下記の例のようにダイアログの結果を待って次の処理を実行したいだけです。
汎用化とかは特に必要なく、一番シンプルな方法でサクッと実現できればOKです。
「削除ボタンがクリックされたら削除確認ダイアログを表示し、OKボタンが押されたら削除処理を実行する」といった簡単なダイアログを想定しています。

const handleDeleteClick = () => {
  const confirmResult = 削除確認ダイアログの表示()
  if (confirmResult === 削除ボタン押された){
      削除処理する
  }
}

ダイアログ

ダイアログのコードです。MUI v5 で作っています。
ダイアログを閉じたとき、キャンセルボタンをクリックしたとき、OKボタンをクリックしたとき、すべてをプロップのonCloseにハンドリングして、ダイアログを閉じた理由を引数で渡すようにしています。

MyDialog.tsx
import { Dialog, DialogTitle, DialogContent, DialogActions, DialogContentText, Button } from '@mui/material'

export type MyDialogProps = {
+  onClose: (value: string) => void
  title?: string
  message?: string
}

export function MyDialog(props: MyDialogProps) {
  const { onClose, title, message } = props

  return (
+    <Dialog open onClose={() => onClose('close')}>
      <DialogTitle>{title}</DialogTitle>
      <DialogContent>
        <DialogContentText>{message}</DialogContentText>
      </DialogContent>
      <DialogActions>
+        <Button onClick={() => onClose('ok')}>OK</Button>
+        <Button onClick={() => onClose('cancel')} autoFocus>
          Cancel
        </Button>
      </DialogActions>
    </Dialog>
  )
}

呼び出し側

ダイアログの呼び出し側の処理です。
ダイアログプロップの onClose に Promise の resolve() を渡してあげるだけです。

App.tsx
import React from 'react'
import { MyDialog, MyDialogProps } from './MyDialog'

export function App() {
+  const [modalConfig, setModalConfig] = React.useState<MyDialogProps | undefined>()

  /**
   * 削除ボタンクリック時の処理
   */
  const handleDeleteClick = async () => {
    const ret = await new Promise<string>((resolve) => {
+      setModalConfig({
        onClose: resolve,
        title: '削除します。よろしいですか?',
        message: '削除すると二度と元に戻せません。'
      })
    })
+    setModalConfig(undefined)
    console.log(ret)
    if (ret === 'ok') {
      console.log('削除する:OK時の処理を実行する')
    }
    if (ret === 'cancel') {
      console.log('削除する:Cancel時の処理を実行する')
    }
  }

  /**
   * その他ボタンクリック時の処理
   */
  const handleOtherClick = async () => {
    const ret = await new Promise<string>((resolve) => {
+      setModalConfig({
+        onClose: resolve,
+        title: '何かします。よろしいですか?',
+        message: '何かすると二度と元に戻せません。'
+      })
    })
+    setModalConfig(undefined)
    console.log(ret)
    if (ret === 'ok') {
      console.log('何かする:OK時の処理を実行する')
    }
    if (ret === 'cancel') {
      console.log('何かする:Cancel時の処理を実行する')
    }
  }

  return (
    <div className="App">
      <button type="button" onClick={handleDeleteClick}>
        Delete Confirm
      </button>

      <button type="button" onClick={handleOtherClick}>
        Other Confirm
      </button>

+      {modalConfig && <MyDialog {...modalConfig} />}
    </div>
  )
}

削除確認ダイアログなんかはよく使うので、専用に特化してしまえばもっとシンプルになります。