ネストされたオブジェクトと配列
Conform は、 name 属性の命名規則を活用することで、ネストされたオブジェクトと配列の両方をサポートしています。
#命名規則
Conform は、データ構造を示すために object.property
および array[index]
の構文を使用します。これらの表記法は、ネストされた配列に対しても組み合わせることができます。例えば、 tasks[0].content
のようになります。フォームデータに ['tasks[0].content', 'Hello World']
というエントリがある場合、構築されるオブジェクトは { tasks: [{ content: 'Hello World' }] }
になります。
しかし、各フィールドの name 属性を手動で設定する必要はありません。 Conform は常に名前を推測してくれるため、生成された名前を全て使用していれば、より良い型安全性が得られます。
#ネストされたオブジェクト
ネストされたフィールドを設定するには、親フィールドのメタデータから getFieldset()
メソッドを呼び出し、名前が自動的に推測される各子フィールドにアクセスしてください。
1import { useForm } from '@conform-to/react';
2import { parseWithZod } from '@conform-to/zod';
3import { z } from 'zod';
4
5const schema = z.object({
6 address: z.object({
7 street: z.string(),
8 zipcode: z.string(),
9 city: z.string(),
10 country: z.string(),
11 }),
12});
13
14function Example() {
15 const [form, fields] = useForm({
16 onValidate({ formData }) {
17 return parseWithZod(formData, { schema });
18 },
19 });
20 const address = fields.address.getFieldset();
21
22 return (
23 <form id={form.id}>
24 {/* name を `address.street` 、`address.zipcode` などに設定します。 */}
25 <input name={address.street.name} />
26 <div>{address.street.errors}</div>
27 <input name={address.zipcode.name} />
28 <div>{address.zipcode.errors}</div>
29 <input name={address.city.name} />
30 <div>{address.city.errors}</div>
31 <input name={address.country.name} />
32 <div>{address.country.errors}</div>
33 </form>
34 );
35}
#配列
フィールドのリストを設定する必要がある場合は、親フィールドのメタデータから getFieldList()
メソッドを呼び出して、名前が自動的に推測される各アイテムフィールドにアクセスできます。リスト内のアイテムを変更したい場合は、 Intent button ページで説明されているように、 insert
、 remove
、 reorder
のインテントも使用できます。
1import { useForm } from '@conform-to/react';
2import { parseWithZod } from '@conform-to/zod';
3import { z } from 'zod';
4
5const schema = z.object({
6 tasks: z.array(
7 z.object({
8 title: z.string(),
9 notes: z.string(),
10 }),
11 ),
12});
13
14function Example() {
15 const [form, fields] = useForm({
16 onValidate({ formData }) {
17 return parseWithZod(formData, { schema });
18 },
19 });
20 const tasks = fields.tasks.getFieldList();
21
22 return (
23 <form id={form.id}>
24 <ul>
25 {tasks.map((task) => (
26 <li key={task.key}>
27 {/* 名前を `tasks[0]` 、 `tasks[1]` などに設定します。 */}
28 <input name={task.name} />
29 <div>{task.errors}</div>
30 </li>
31 ))}
32 </ul>
33 </form>
34 );
35}
#ネストされた配列
ネストされた配列に対して、 getFieldset()
と getFieldList()
の両方を組み合わせて使用することもできます。
1import { useForm } from '@conform-to/react';
2
3function Example() {
4 const [form, fields] = useForm();
5 const todos = fields.todos.getFieldList();
6
7 return (
8 <form id={form.id}>
9 <ul>
10 {todos.map((todo) => {
11 const todoFields = todo.getFieldset();
12
13 return (
14 <li key={todo.key}>
15 <input name={todoFields.title.name} />
16 <div>{todoFields.title.errors}</div>
17 <input name={todoFields.notes.name} />
18 <div>{todoFields.notes.errors}</div>
19 </li>
20 );
21 })}
22 </ul>
23 </form>
24 );
25}