開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. Javascript >
  4. [JavaScript]フォームの中身をJSONに変換する
no-image

[JavaScript]フォームの中身をJSONに変換する

こんにちは。タカギです。

今回は小ネタです。
HTMLのフォーム入力値をお手軽にJSONに変換してAPIコールする方法について、素のHTML+JSのパターン・Reactを使ったパターンの2通りを紹介します。

※ あまり推奨されるコードは出てきません
※ 簡略化のため、CSRF対策やバリデーションは省略します

素のHTMLの場合

例えばこんなフォームがあったとします。

<h1>お問合せフォーム</h1>
<form id="inquiry">
    <label>
        お名前
        <input type="text" name="name">
    </label>
    <label>
        メールアドレス
        <input type="email" name="email">
    </label>
    <label>
        お問合せ内容
        <textarea name="content"></textarea>
    </label>
    <button type="submit">送信</button>
</form>

このフォームを単にHTMLでサブミットすれば良いというのであれば話は簡単ですが、
そうではなくこの入力値をJSONに変換しバックエンドAPIをコールする必要がある場合があります。
その場合、JavaScriptのFormDataを使用してこのように書けます。

/**
 * @type {HTMLFormElement}
 */
const form = document.getElementById("inquiry");
form.addEventListener("submit", async ev => {
    ev.preventDefault();

    const formData = new FormData(form);
    const data = Object.fromEntries(formData.entries());

    console.log(data); // {name: 'test', email: 'test@example.com', content: 'xxx'}

    try {
        // APIコール
        await window.fetch("/", {
            method: "POST",
            body: JSON.stringify(data),
        });

        window.alert("送信しました。");

        // 完了時に入力値をクリア
        form.reset();

    } catch (e) {
        console.log(e);
    }
});

HTMLFormElementからFormDataを生成し、FormData.entries()とObject.fromEntries()を使ってオブジェクトに変換できるのがポイントです。
各入力項目を1つずつ手作業で抜き出すことなく、一発でJSONに変換できて便利です。

Reactの場合

同じことがReactでも行えます。

import { FormEvent } from "react";

export default function ExampleForm() {
  const handleSubmit = async (ev: FormEvent<HTMLFormElement>) => {
    const form = ev.target as HTMLFormElement;
    const formData = new FormData(form);
    const data = Object.fromEntries(formData.entries());

    console.log(data);

    try {
      // APIコール
      await window.fetch("/", {
        method: "POST",
        body: JSON.stringify(data),
      });

      window.alert("送信しました。");

      // 完了時に入力値をクリア
      form.reset();
    } catch (e) {
      console.log(e);
    }
  };

  return (
    <>
      <h1>お問合せフォーム</h1>
      <form onSubmit={handleSubmit}>
        <label>
          お名前
          <input type="text" name="name" />
        </label>
        <label>
          メールアドレス
          <input type="email" name="email" />
        </label>
        <label>
          お問合せ内容
          <textarea name="content" />
        </label>
        <button type="submit">送信</button>
      </form>
    </>
  );
}

これはかなり見慣れない書き方だと思いますし、あまり推奨できる書き方ではありません。 React.useState()を使ってReactで状態管理をせず、生のDOMに状態を持たせています。
React.useState()を使いReactのstateを“信頼できる唯一の情報源 (single source of truth)”とするのを「制御されたコンポーネント(controlled component)」と呼ぶのに対し、
今回のような生DOMに状態を持たせるコンポーネントを「非制御コンポーネント(uncontrolled component)」と呼びます。

一般的には可能な限りcontrolled componentで書くことが推奨されていると思いますが、React公式ドキュメントでも

制御されたコンポーネントは、あらゆる種類のデータの変更に対してイベントハンドラを書き、あらゆる入力状態を React コンポーネントに通してやる必要があるため、時としてうんざりすることがあります。このことは既存のコードベースを React に変換する場合や、React アプリケーションを非 React のライブラリと統合する場合に、特に問題化します。これらの状況においては、入力フォームを実装する代替手段である非制御コンポーネントを検討してみてください。

と言っています。
うんざりしている時であれば使用も許されるそうなので、選択肢の一つとして頭に入れておいても良いかもしれません。

生DOMに状態を持つため入力値をJavaScriptから扱うことがやや面倒になりReactの恩恵はほぼ受けられませんが、簡単なクライアントバリデーションはHTML5でできますし、入力値のクリア、完了メッセージの表示などもReactの機能は使わずに生JSのみで実現しています。
要件次第ではこの書き方+α程度で十分なケースもあるかもしれません。
(個人的な観測範囲では、そこそこある印象です。)

ここまで読んでいて気づいた方がほとんどだと思いますが、これで十分なケース(このレベルの単純なフォーム)ではReactを導入することで得られるメリットはほぼありません。
適切な技術選定、していきたいですね。

まとめ

  • FormData.entries()とObject.fromEntries()でフォーム入力値をJSONに変換できてちょっと便利
  • 非制御コンポーネント(uncontrolled component)というReactを頑張らない選択肢
  • 単純なフォームであればReactを導入する必要がない(こともある)

フレームワークを使わずにフォームを実装する試みは別記事でも紹介しておりますので、よろしければそちらも見ていただければと思います。
ここまでお読みいただきありがとうございました。

TOPに戻る