ガイド / インテントボタン

インテントボタン

送信ボタンがフォームの送信を行う際、それは submitter として機能し、フォームデータに含まれることになります。

#送信のインテント

submitter は、インテント(意図)に基づいて異なる振る舞いでフォームを拡張したい場合に特に便利です。

1import { useForm } from '@conform-to/react';
2
3function Product() {
4  const [form] = useForm({
5    onSubmit(event, { formData }) {
6      event.preventDefault();
7
8      switch (formData.get('intent')) {
9        case 'add-to-cart':
10          // カートに追加
11          break;
12        case 'buy-now':
13          // 購入
14          break;
15      }
16    },
17  });
18
19  return (
20    <form id={form.id}>
21      <input type="hidden" name="productId" value="rf23g43" />
22      <button type="submit" name="intent" value="add-to-cart">
23        Add to Cart
24      </button>
25      <button type="submit" name="intent" value="buy-now">
26        Buy now
27      </button>
28    </form>
29  );
30}

#フォームのコントロール

Conform は、フィールドのバリデーションや削除など、すべてのフォームコントロールに対して送信のインテントを利用します。これは、ボタンに予約された名前を与え、インテントを値としてシリアライズすることで成されます。設定を簡素化するために、 Conform は form.validateform.resetform.insert などの一連のフォームコントロールヘルパーを提供します。

バリデート インテント

バリデーションをトリガーするには、バリデート インテントを使用してボタンを構成できます。

1import { useForm } from '@conform-to/react';
2
3function EmailForm() {
4  const [form, fields] = useForm();
5
6  return (
7    <form id={form.id}>
8      <input name={fields.email.name} />
9      <button {...form.validate.getButtonProps({ name: fields.email.name })}>
10        Validate Email
11      </button>
12    </form>
13  );
14}

ボタンがクリックされると、 Conform は予約された名前でシリアライズされたインテントを識別し、メールフィールドを検証済みとしてマークすることによりバリデーションをトリガーし、メールが無効である場合はエラーメッセージを返します。

しかし、ユーザーがフィールドを離れた時点でバリデーションをトリガーしたい場合は、バリデート インテントを直接トリガーすることもできます。

1import { useForm } from '@conform-to/react';
2
3function EmailForm() {
4  const [form, fields] = useForm();
5
6  return (
7    <form id={form.id}>
8      <input
9        name={fields.email.name}
10        onBlur={(event) => form.validate({ name: event.target.name })}
11      />
12    </form>
13  );
14}

reset および update インテント

reset および update のインテントを使ってフィールドを変更することもできます。

1import { useForm } from '@conform-to/react';
2
3export default function Tasks() {
4  const [form, fields] = useForm();
5
6  return (
7    <form id={form.id}>
8      <button {...form.reset.getButtonProps()}>Reset form</button>
9      <button
10        {...form.reset.getButtonProps({
11          name: fields.tasks.name,
12        })}
13      >
14        Reset field (including nested / list field)
15      </button>
16      <button
17        {...form.update.getButtonProps({
18          name: fields.agenda.name,
19          value: {
20            title: 'My agenda',
21            description: 'This is my agenda',
22          },
23        })}
24      >
25        Update field (including nested / list field)
26      </button>
27      <button
28        {...form.update.getButtonProps({
29          validated: false,
30        })}
31      >
32        Clear all error
33      </button>
34    </form>
35  );
36}

両方のインテントを使用するには、フィールドメタデータから key を使って入力を設定する必要があります。 Conform はこのキーに依存して、更新された initialValue で input を再マウントするための React への通知を行います。唯一の例外は、 useInputControl フックを使用して制御された入力を設定している場合で、 key が変更されると値がリセットされます。

insert、remove、および reorder (並び替え) インテント

フィールドリストを操作するには、 insertremovereorder のインテントを使用できます。

1import { useForm } from '@conform-to/react';
2import { parseWithZod } from "@conform-to/zod";
3import { z } from "zod";
4
5const todosSchema = z.object({
6  title: z.string(),
7  tasks: z.array(z.string()),
8});
9
10export default function Tasks() {
11  const [form, fields] = useForm({
12    onValidate({ formData }) {
13      return parseWithZod(formData, { schema: todosSchema });
14    },
15    shouldValidate: "onBlur",
16  });
17  const tasks = fields.tasks.getFieldList();
18
19  return (
20    <form id={form.id} onSubmit={form.onSubmit}>
21      <ul>
22        {tasks.map((task, index) => (
23          <li key={task.key}>
24            <input name={task.name} />
25            <button
26              {...form.reorder.getButtonProps({
27                name: fields.tasks.name,
28                from: index,
29                to: 0,
30              })}
31            >
32              Move to top
33            </button>
34            <button
35              {...form.remove.getButtonProps({
36                name: fields.tasks.name,
37                index,
38              })}
39            >
40              Delete
41            </button>
42          </li>
43        ))}
44      </ul>
45      <button
46        {...form.insert.getButtonProps({
47          name: fields.tasks.name,
48        })}
49      >
50        Add task
51      </button>
52      <button>Save</button>
53    </form>
54  );
55}