🌟

Reactでモーダルが閉じるまで処理を待機させる方法

に公開

はじめに

今回はかなり難しいです。
非同期・Promise・useState・props・コールバック関数・移譲、あたりを知っている前提になるため、何を言っているいかわからない場合は先にこれらの記事を読むことをお勧めします。
Promiseについては後日、私も書きたいと思っていますが、今回結構ハマったのでタイトルの答えを先に公開します。

考え方

モーダルの結果、画面遷移を伴う場合は何も難しくありません。
普通にnavigateなり、aタグなりでロケーションを変えるだけです。

しかし、同じ画面で独自仕様の確認モーダルを開いて、モーダルで押されたボタンによって処理を進めるか決めたいとなると、その行で停止してもらう必要があります。

停止といえばajax通信で使うawait/asyncがパッと思いつきましたが、今回は独自関数で止めたい上に、再開するタイミングもカスタマイズしなければいけません。

そこでPromiseを独自で生成し、そのresolve,rejectのコールバック関数をモーダルのコンポーネントへ移譲します。

具体的なコード

親コンポーネント
const [modalResultFunc,setModalResultFunc] = useState(null);

// (中略)
  const getModalResult = () => {
    return new Promise(
      (resolve,reject) => {
        // 関数をstateに入れる時にはオブジェクトでラップしないとpropsでnullがわたる罠があった。
        setModalResultFunc({resolve, reject});

        // 確認モーダルを開く
        modalOpen();
      }
    )
  }

// (中略)
    // 確認モーダルで「OK」ボタンを押下された場合のみ先へ進み、「Cancel」ボタンを押下されたら中断する。
    await getModalResult()
      .then((result) => {
        // OKボタン発動時にthenが発火する。ここにOKボタン押下時の処理を記述する。
        alert('OKが押された');

        // DB登録処理などを書く。
        registFormData();
      })
      .catch((error) => {
        // キャンセルボタン押下時に発火する。ここに中断処理を記述する。
        alert('キャンセルが押された');
        return;
      })
      .finally(() => {
        // モーダルを閉じる処理を書く。
        modalClose();
      })

// --------------------------------------------------------------------

// (中略)
// Promiseの結果を決める関数自体を子コンポーネントに移譲する。
        <SubmitPreview
          modalResultFunc={modalResultFunc}
        ></SubmitPreview>
モーダルコンポーネント
// 親から受け取ったPromiseの関数をonClickに設定する。
<button onClick={() => {props.modalResultFunc.resolve()}}>OK</button>
<button onClick={() => {props.modalResultFunc.reject()}}>キャンセル</button>

おわりに

いかがでしょうか。Promiseを自分で書く機会はそうそうないため、いざ自作しようとするとかなり難しいと思います。
基礎の集大成ですね。

株式会社ONE WEDGE

【Serverlessで世の中をもっと楽しく】 ONE WEDGEはServerlessシステム開発を中核技術としてWeb系システム開発、AWS/GCPを利用した業務システム・サービス開発、PWAを用いたモバイル開発、Alexaスキル開発など、元気と技術力を武器にお客様に真摯に向き合う価値創造企業です。
https://onewedge.co.jp

Discussion