Perseid と React を使用してユーザー フィードバック フォームを構築する

DDD
リリース: 2024-09-19 03:45:06
オリジナル
981 人が閲覧しました

このガイドでは、FormikReact Hook Form の強力な代替手段である @perseid/form ライブラリを使用して動的なユーザー フィードバック フォームを構築する手順を説明します。 @perseid/form を使用すると、フォームの状態、検証、条件付きレンダリングの管理がどのように簡単になるかがわかります。これから作成するフォームでは、ユーザーにサービスを評価し、フィードバックを提供するよう求めます。評価に応じて、「ありがとう」メッセージが表示されるか、ユーザーに追加のフィードバックを提供するよう求められます。

?始めましょう!


ステップ 1: フォーム構成のセットアップ

最初のステップは、フォーム構成を定義することです。この構成は、フィールド、ステップ、それらの間のフローなど、フォームの動作の概要を示します。ここでは、ユーザーの評価に基づいた 条件ロジック を使用して、評価とレビューのフィールドを作成します。また、肯定的なフィードバックと否定的なフィードバックの両方のメッセージも定義します。

設定コードは次のとおりです:

import { type Configuration } from "@perseid/form";

const formConfiguration: Configuration = {
  // Root step-the form will start from there.
  root: "feedback",
  // Callback triggered on form submission.
  onSubmit(data) {
    alert(`Submitting the following JSON: ${JSON.stringify(data)}`);
    return Promise.resolve();
  },
  // `fields` define the data model the form is going to deal with.
  // Expect the submitted data JSON to match this schema.
  fields: {
    rating: {
      type: "integer",
      required: true,
    },
    review: {
      type: "string",
      required: true,
      // Display this field only if condition is met...
      condition: (inputs) =>
        inputs.rating !== null && (inputs.rating as number) < 3,
    },
    // Type `null` means that the value of this field will not be included in submitted data.
    submit: {
      type: "null",
      submit: true,
    },
    message_good: {
      type: "null",
    },
    message_bad: {
      type: "null",
    },
  },
  // Now that fields are defined, you can organize them in a single or multiple steps,
  // depending on the UI you want to build!
  steps: {
    feedback: {
      fields: ["rating", "review", "submit"],
      // Whether to submit the form at the end of this step.
      submit: true,
      // Next step is conditionned to previous user inputs...
      nextStep: (inputs) =>
        (inputs.rating as number) < 3 ? "thanks_bad" : "thanks_good",
    },
    thanks_good: {
      fields: ["message_good"],
    },
    thanks_bad: {
      fields: ["message_bad"],
    },
  },
};

ログイン後にコピー

この構成では:

  • フォームはフィードバックのステップから始まります。
  • フォームには、評価 (必須) とレビュー (評価が 3 未満でない限りオプション) の 2 つのフィールドが含まれています。
  • 評価に基づいて、フォームは「良い」または「悪い」フィードバック メッセージに移動します。
  • フォームを送信すると、送信されたデータによって簡単なアラートがトリガーされます。

ここで理解すべき重要な点は、fields プロパティの機能です。これは、送信されるデータの構造を定義し、本質的にデータ モデルとして機能します。対照的に、steps プロパティはフォームのフローの概要を示し、これらのフィールドがユーザーにどのように表示されるかを決定します。


ステップ 2: フォームの React コンポーネントを作成する

構成が完了したので、フォームをレンダリングする実際の UI を構築します。 @perseid/form/react を使用すると、カスタム フィールド コンポーネントを作成して、フォームの各部分のユーザー インタラクションを管理できます。

これがコア React コンポーネントです:

import React from "react";
import Form, { type FormFieldProps } from "@perseid/form/react";

// The actual React component, used to build the UI!
function Field(props: FormFieldProps): JSX.Element {
  const { path, engine, value, status } = props;
  const [currentRating, setCurrentRating] = React.useState(0);

  // Display a different element depending on the field...

  if (path === "thanks_good.1.message_good") {
    return (
      <div className="message">
        <h1>Thanks for the feedback ?</h1>
        <p>We are glad you enjoyed!</p>
      </div>
    );
  }

  if (path === "thanks_bad.1.message_bad") {
    return (
      <div className="message">
        <h1>We're sorry to hear that ?</h1>
        <p>We'll do better next time, promise!</p>
      </div>
    );
  }

  if (path === "feedback.0.rating") {
    return (
      // Depending on the field status, define some extra classes for styling...
      <div
        className={`rating ${status === "error" ? "rating--error" : ""}`}
        onMouseLeave={() => {
          setCurrentRating((value as number | null) ?? 0);
        }}
      >
        <h1>How would you rate our service?</h1>
        {[1, 2, 3, 4, 5].map((rating) => (
          <span
            key={rating}
            className={`rating__star ${
              currentRating >= rating ? "rating__star--active" : ""
            }`}
            onMouseEnter={() => {
              setCurrentRating(rating);
            }}
            onClick={() => {
              // On click, notify the form engine about new user input.
              engine.userAction({ type: "input", path, data: rating });
            }}
          ></span>
        ))}
      </div>
    );
  }

  if (path === "feedback.0.review") {
    return (
      <div className={`review ${status === "error" ? "review--error" : ""}`}>
        <label>Could you tell us more?</label>
        <textarea
          onChange={(e) =>
            engine.userAction({ type: "input", path, data: e.target.value })
          }
        />
      </div>
    );
  }

  // path === 'feedback.0.submit'
  return (
    <button
      className="submit"
      onClick={() => {
        engine.userAction({ type: "input", path, data: true });
      }}
    >
      Submit
    </button>
  );
}
ログイン後にコピー

ここで、Field コンポーネントはパス プロパティを使用して何をレンダリングするかを決定します。

  • ユーザーが星評価を選択できる評価コンポーネント。
  • ユーザーが追加のフィードバックを提供するためのテキストエリア。

評価に基づいて表示される「ありがとう」メッセージ。フォームはユーザー入力に基づいてフィールドとステップを動的に調整します。

かなりクールですね?

Building a User Feedback Form with Perseid and React


ステップ 3: アプリケーションの実行

フォーム構成とコンポーネントの準備ができたので、それらを基本的な React アプリに統合しましょう。フォームを初期化してレンダリングするコードは次のとおりです:

import { createRoot, type Root } from "react-dom/client";

// Let's run the app!
let app: Root;

// Creating React root...
const container = document.querySelector("#root") as unknown as HTMLElement;
app = createRoot(container);
app.render(
  // Router is the main component for any Perseid app.
  <Form Field={Field} configuration={formConfiguration} />
);
ログイン後にコピー

このコードは、React の createRoot API を使用してフォームを DOM にマウントします。 Form コンポーネントは、構成と Field コンポーネントを接続し、その他すべてを処理します。

ステップ 4: スタイルの追加

アプリのロジックはできましたが、今コードを実行すると、それが少し...生々しいことがわかりますか?

Building a User Feedback Form with Perseid and React

それでは、いくつかのスタイルとアニメーションを追加してフォームを改造してみましょう!以下は、より魅力的なものにするシンプルなスタイルシートです:

// A few animations for fun...

@keyframes swipe-out {
  0% {
    opacity: 1;
    transform: translateX(0);
  }
  75% {
    opacity: 0;
    transform: translateX(-100%);
  }
  100% {
    opacity: 0;
    transform: translateX(-100%);
  }
}

@keyframes swipe-in-one {
  0% {
    opacity: 0;
    transform: translateX(100%);
  }
  75% {
    transform: translateX(0);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes swipe-in-two {
  0% {
    opacity: 0;
    transform: translateX(0);
  }
  75% {
    transform: translateX(-100%);
  }
  100% {
    opacity: 1;
    transform: translateX(-100%);
  }
}

@keyframes bubble-in {
  0% {
    transform: scale(0.5);
  }
  75% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1);
  }
}

@keyframes fade-in {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

// Some global basic styling...

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  display: grid;
  height: 100vh;
  color: #aaaaaa;
  align-items: center;
  font-family: "Helvetica", sans-serif;
}

// And form-specific styling.

.perseid-form {
  width: 100%;
  margin: auto;

  &__steps {
    display: flex;
    overflow: hidden;
  }

  &__step {
    min-width: 100%;
    padding: 1rem 3rem;
    animation: 500ms ease-in-out forwards swipe-out;

    &__fields {
      display: grid;
      row-gap: 2rem;
    }
  }

  &__step[class*="active"]:first-child {
    animation: 500ms ease-in-out forwards swipe-in-one;
  }
  &__step[class*="active"]:last-child:not(:first-child) {
    animation: 500ms ease-in-out forwards swipe-in-two;
  }
}

.submit {
  border: none;
  cursor: pointer;
  padding: 1rem 2rem;
  border-radius: 8px;
  color: #fefefe;
  font-size: 1.25rem;
  background: #46c0b0;
  justify-self: flex-end;
  transition: all 250ms ease-in-out;

  &:hover {
    background: #4cccbb;
  }
}

.rating {
  position: relative;
  padding: 0.25rem 0;

  &__star {
    cursor: pointer;
    display: inline-block;
    font-size: 2rem;
    min-width: 2rem;
    min-height: 2rem;

    &::after {
      content: "⚪️";
    }

    &--active {
      animation: 250ms ease-in-out forwards bubble-in;
      &::after {
        content: "?";
      }
    }
  }

  &[class*="error"] {
    &::after {
      left: 0;
      bottom: -1.5rem;
      color: #f13232;
      position: absolute;
      font-size: 0.75rem;
      content: "? This field is required";
      animation: 250ms ease-in-out forwards fade-in;
    }
  }
}

.review {
  display: grid;
  row-gap: 1rem;
  position: relative;
  animation: 250ms ease-in-out forwards fade-in;

  label {
    font-size: 1.25rem;
  }

  textarea {
    resize: none;
    min-height: 5rem;
    border-radius: 8px;
    border: 1px solid #46c0b0;
    transition: all 250ms ease-in-out;
  }

  &[class*="error"] {
    &::after {
      left: 0;
      bottom: -1.5rem;
      color: #f13232;
      position: absolute;
      font-size: 0.75rem;
      content: "? This field is required";
      animation: 250ms ease-in-out forwards fade-in;
    }
  }
}

@media screen and (min-width: 30rem) {
  .perseid-form {
    max-width: 30rem;
  }
}
ログイン後にコピー

そして出来上がり?


結論

おめでとうございます! ? Perseid と React を使用して動的なユーザー フィードバック フォームを構築しました。

このチュートリアルでは、次の方法について説明しました。

  • 条件付きロジックを使用してフォーム構成を定義します。
  • ユーザー操作を処理するカスタム React コンポーネントを構築します。
  • アプリでフォームをレンダリングし、アニメーションとカスタム CSS でスタイルを設定します。

ユースケースに合わせて、追加のフィールドや手順を自由に試してみてください。素晴らしいフォームの構築を楽しんでください。 ?


  • ?他の例
  • ✅ 完全なドキュメント
  • ? Discordに参加してください
  • ? GitHub でプロジェクトにスターを付ける
  • ❤️ スポンサー ペルセイド

以上がPerseid と React を使用してユーザー フィードバック フォームを構築するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!