ReactとPHPで作るお問い合わせフォーム

本記事では、Reactを使ったお問い合わせフォームの作成方法を紹介します。このフォームは、Vue.jsとPHPで作るお問い合わせフォームを元に、Reactで実装したものです。


使用技術とバージョン情報

  • React: 17.x (CDN経由で最新バージョンを使用 ※テストは17.0.2)
  • Tailwind CSS: 3.x (CDN経由で最新バージョンを使用 ※テストは3.4.15)
  • PHP: 8.2.22
  • サーバー環境: エックスサーバー

Vue.js版との違い

React版のフォームは、Vue.js版と見た目や動きは同じですが、以下の点が異なります:

  1. Reactの特性を活用:
  • JSXによる宣言的なUI記述。
  • コンポーネントの状態をuseStateで管理。
  1. 同様の動作:
  • 入力画面、確認画面、完了画面の3ステップ構成。
  • PHPを利用したバックエンド処理。
  1. ファイル構成:
  • ReactとBabelを使用し、HTML内にJSXを記述。

完成するフォームの特徴

  1. 3ステップ構成:
  • 入力画面: 名前、メールアドレス、お問い合わせ内容を入力。
  • 確認画面: 入力内容を確認して送信または修正が可能。
  • 完了画面: 問い合わせ送信完了のメッセージを表示。
  1. レスポンシブ対応:
  • Tailwind CSSを活用して、PC・タブレット・スマートフォンでも見やすいデザイン。
  1. Reactによるリアクティブな画面遷移:
  • 現在のフォームステップを管理し、適切なコンポーネントをレンダリング。

動きの説明

Reactを使用したフォームは以下の3つのステップで動作します:

  1. 入力画面
    ユーザーは名前、メールアドレス、お問い合わせ内容を入力します。useStateで入力値をリアルタイムに管理します。
  2. 確認画面
    入力された内容を確認し、修正が必要な場合は戻ることができます。問題がなければ「送信する」をクリック。
  3. 完了画面
    問い合わせが送信されると「送信完了」メッセージが表示されます。フォームをリセットして最初の画面に戻ることも可能です。

スクリーンショット

入力画面

確認画面

完了画面


フロントエンドの実装

以下は、Reactを使用したフロントエンドのコードです。

index.html

ReactとTailwind CSSをCDN経由で読み込み、フォームの動作をブラウザ上で確認できるようにします。

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React お問い合わせフォーム</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>

<body class="bg-gray-100 min-h-screen flex items-center justify-center">
  <div id="root" class="container mx-auto p-4 max-w-screen-md"></div>

  <script type="text/babel">
    const { useState } = React;

    function App() {
      const [currentStep, setCurrentStep] = useState("input");
      const [formData, setFormData] = useState({
        name: "",
        email: "",
        message: ""
      });

      const handleInputChange = (e) => {
        const { name, value } = e.target;
        setFormData({ ...formData, [name]: value });
      };

      const resetForm = () => {
        setFormData({ name: "", email: "", message: "" });
        setCurrentStep("input");
      };

      const submitForm = async () => {
        try {
          const response = await fetch("backend/contact.php", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(formData)
          });
          const data = await response.json();
          if (data.success) {
            setCurrentStep("complete");
          } else {
            alert("送信に失敗しました: " + (data.error || "不明なエラー"));
            setCurrentStep("input");
          }
        } catch (error) {
          alert("エラーが発生しました。");
          setCurrentStep("input");
        }
      };

      return (
        <div className="bg-white shadow-md rounded p-6 w-full max-w-md mx-auto">
          {currentStep === "input" && (
            <>
              <h1 className="text-2xl font-bold mb-4">お問い合わせフォーム</h1>
              <form
                onSubmit={(e) => {
                  e.preventDefault();
                  setCurrentStep("confirm");
                }}
              >
                <div className="mb-4">
                  <label htmlFor="name" className="block text-sm font-medium text-gray-700">名前:</label>
                  <input
                    type="text"
                    id="name"
                    name="name"
                    value={formData.name}
                    onChange={handleInputChange}
                    required
                    className="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500"
                  />
                </div>
                <div className="mb-4">
                  <label htmlFor="email" className="block text-sm font-medium text-gray-700">メールアドレス:</label>
                  <input
                    type="email"
                    id="email"
                    name="email"
                    value={formData.email}
                    onChange={handleInputChange}
                    required
                    className="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500"
                  />
                </div>
                <div className="mb-4">
                  <label htmlFor="message" className="block text-sm font-medium text-gray-700">お問い合わせ内容:</label>
                  <textarea
                    id="message"
                    name="message"
                    value={formData.message}
                    onChange={handleInputChange}
                    required
                    className="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500"
                  />
                </div>
                <button
                  type="submit"
                  className="w-full bg-indigo-600 text-white py-2 px-4 rounded hover:bg-indigo-700"
                >
                  確認画面へ
                </button>
              </form>
            </>
          )}

          {currentStep === "confirm" && (
            <>
              <h1 className="text-2xl font-bold mb-4">内容の確認</h1>
              <p className="mb-2"><strong>名前:</strong> {formData.name}</p>
              <p className="mb-2"><strong>メールアドレス:</strong> {formData.email}</p>
              <p className="mb-4"><strong>お問い合わせ内容:</strong> {formData.message}</p>
              <div className="flex space-x-4">
                <button
                  onClick={() => setCurrentStep("input")}
                  className="w-1/2 bg-gray-600 text-white py-2 px-4 rounded hover:bg-gray-700"
                >
                  戻る
                </button>
                <button
                  onClick={submitForm}
                  className="w-1/2 bg-indigo-600 text-white py-2 px-4 rounded hover:bg-indigo-700"
                >
                  送信する
                </button>
              </div>
            </>
          )}

          {currentStep === "complete" && (
            <>
              <h1 className="text-2xl font-bold mb-4">送信が完了しました</h1>
              <p>お問い合わせいただきありがとうございます。</p>
              <button
                onClick={resetForm}
                className="mt-4 w-full bg-indigo-600 text-white py-2 px-4 rounded hover:bg-indigo-700"
              >
                フォームに戻る
              </button>
            </>
          )}
        </div>
      );
    }

    ReactDOM.render(<App />, document.getElementById("root"));
  </script>
</body>

</html>

バックエンドの実装

バックエンドでは、PHPを使用して問い合わせ内容を処理します。

contact.php

<?php
header('Content-Type: application/json');

$data = json_decode(file_get_contents('php://input'), true);

if (empty($data['name']) || empty($data['email']) || empty($data['message'])) {
    echo json_encode(['success' => false, 'error' => '入力内容が不完全です。']);
    exit;
}

// 管理者への通知メール
$toAdmin = 'admin@example.com'; // 仮の送信先アドレス
$subjectAdmin = 'お問い合わせフォームからのメッセージ';
$messageAdmin = "名前: {$data['name']}\nメールアドレス: {$data['email']}\nメッセージ: {$data['message']}";
$headersAdmin = 'From: noreply@example.com'; // 仮のFromアドレス

$mailToAdmin = mail($toAdmin, $subjectAdmin, $messageAdmin, $headersAdmin);

// 問い合わせ者への自動返信メール
$toUser = $data['email'];
$subjectUser = 'お問い合わせありがとうございます';
$messageUser = "{$data['name']} 様\n\nお問い合わせありがとうございます。\n以下の内容で受け付けました。\n----------------------\nお名前: {$data['name']}\nメールアドレス: {$data['email']}\nお問い合わせ内容:\n{$data['message']}\n----------------------\n\n担当者より折り返しご連絡いたします。";
$headersUser = 'From: noreply@example.com'; // 仮のFromアドレス

$mailToUser = mail($toUser, $subjectUser, $messageUser, $headersUser);

if ($mailToAdmin && $mailToUser) {
    echo json_encode(['success' => true]);
} else {
    echo json_encode(['success' => false, 'error' => 'メール送信に失敗しました。']);
}

まとめ

本記事では、Vue.jsとPHPで作るお問い合わせフォームのReact版を紹介しました。Reactの特徴であるJSXや状態管理を活用しながら、Tailwind CSSとPHPを組み合わせて簡単かつ柔軟なフォームを構築できます。

コメント

タイトルとURLをコピーしました