Reactのクイズ処理から学ぶ、Promiseとtry…catchの連携メモ

Reactの公式サンプルコードで気になった処理があったので、どのような処理を行なっているかをメモします。

内容は、「問題の答えを送信し、正解か不正解かによって表示する内容を出し分ける」という簡単なクイズアプリ。

表示にはJSXが使われていますが、処理の部分はJavaScript(Promiseやtry…catch)で書かれています。

目次

JavaScript(JSX)のコード

上記のサンプルコードはこちら。

import { useState } from 'react';

export default function Form() {
  const [answer, setAnswer] = useState('');
  const [error, setError] = useState(null);
  const [status, setStatus] = useState('typing');

  if (status === 'success') {
    return <h1>That's right!</h1>
  }

  async function handleSubmit(e) {
    e.preventDefault();
    setStatus('submitting');
    try {
      await submitForm(answer);
      setStatus('success');
    } catch (err) {
      setStatus('typing');
      setError(err);
    }
  }

  function handleTextareaChange(e) {
    setAnswer(e.target.value);
  }

  return (
    <>
      <h2>City quiz</h2>
      <p>
        In which city is there a billboard that turns air into drinkable water?
      </p>
      <form onSubmit={handleSubmit}>
        <textarea
          value={answer}
          onChange={handleTextareaChange}
          disabled={status === 'submitting'}
        />
        <br />
        <button disabled={
          answer.length === 0 ||
          status === 'submitting'
        }>
          Submit
        </button>
        {error !== null &&
          <p className="Error">
            {error.message}
          </p>
        }
      </form>
    </>
  );
}

function submitForm(answer) {
  // Pretend it's hitting the network.
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let shouldError = answer.toLowerCase() !== 'lima'
      if (shouldError) {
        reject(new Error('Good guess but a wrong answer. Try again!'));
      } else {
        resolve();
      }
    }, 1500);
  });
}

処理の流れ

1. ユーザーがフォームで回答を入力し、「Submit」を押す

<form onSubmit={handleSubmit}>

フォームが送信されると、onSubmitに登録されたhandleSubmit関数が呼ばれます。

2. handleSubmit関数(非同期関数)

async function handleSubmit(e) {
  e.preventDefault();          // デフォルト動作(フォームの送信)を無効化
  setStatus('submitting');     // 送信中ステータスに変更(入力や送信ボタンを制限)

  try {
    await submitForm(answer);  // ここで submitForm の非同期処理が完了するまで待つ
    setStatus('success');      // 成功したら成功ステータスに切替
  } catch (err) {
    setStatus('typing');       // エラーが起きたら入力可能な状態に戻す
    setError(err);             // エラー情報を保存して画面に表示
  }
}

補足:基本的なtry…catchの使い方。

try {
  // ここにエラーが起こるかもしれない処理を書く
} catch (error) {
  // エラーが起きたときに実行される
}

tryブロック内のコードが実行され、そこで例外が発生すると、catchブロック内のコードが実行されます。

ここで注目すべきはawait submitForm(answer)の部分です。
submitForm はPromiseを返す非同期関数なので、完了するまで待ちます。

submitFormで処理に問題なければ正解、エラーが返ってくればcatchが実行され不正解が表示されるという仕組みです。

3.submitForm 関数(Promise を返す非同期処理)

function submitForm(answer) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let shouldError = answer.toLowerCase() !== 'lima';
      if (shouldError) {
        reject(new Error('Good guess but a wrong answer. Try again!'));
      } else {
        resolve();  // 正解時は何も返さず resolve
      }
    }, 1500);  // 1.5秒後に判定
  });
}
  • 正解は'lima'です。
  • 不正解ならエラーを発生(reject())。
  • 正解なら resolve() で完了通知。

不正解の場合、new Error()でエラーオブジェクトを生成し、handleSubmit関数のcatch(err)でその内容を受け取れるようになっています。

補足:基本的なPromise()の使い方。

const promise = new Promise((resolve, reject) => {
  // 非同期処理
  if (成功) {
    resolve(結果);   // 成功したときに呼ばれる
  } else {
    reject(エラー);   // 失敗したときに呼ばれる
  }
});

なぜPromiseを使って遅延しているのか

実際のWebアプリでは、フォーム送信後にサーバーにデータを送る処理(=非同期通信)が入ります。

おそらく、「サーバーに問い合わせて結果が返ってくるまで時間がかかる」という状況を模擬(シミュレーション)しているのだと思われます。

  1. フォームの回答を送信
  2. tryではawaitPromiseの処理が終わるまで待っている
  3. Promiseで処理が完了
  4. Promiseresolve()が返れば、tryが実行されて正解処理
  5. Promisereject()が返れば、catchが実行されて不正解処理

という具合です。

おすすめWEBスクール

WEB制作やWEBデザインを学びたいなら、SNSでも話題の「デイトラ」がおすすめ!
どのコースも10万円前後と業界最安値で、副業や転職に向けて十分なスキルを身につけることができます。

役に立ったら他の方にシェア

お気軽にコメントどうぞ

コメントする

目次