ガイド / ファイルのアップロード

ファイルのアップロード

ファイルアップロードを扱うには、フォームの encType 属性を multipart/form-data に設定し、メソッドは POST である必要があります。

#構成

ファイル input の設定は、他の input と何ら変わりません。

1import { useForm } from '@conform-to/react';
2import { parseWithZod } from '@conform-to/zod';
3import { z } from 'zod';
4
5const schema = z.object({
6  profile: z.instanceof(File, { message: 'Profile is required' }),
7});
8
9function Example() {
10  const [form, fields] = useForm({
11    onValidate({ formData }) {
12      return parseWithZod(formData, { schema });
13    },
14  });
15
16  return (
17    <form method="POST" encType="multipart/form-data" id={form.id}>
18      <div>
19        <label>Profile</label>
20        <input type="file" name={fields.profile.name} />
21        <div>{fields.profile.error}</div>
22      </div>
23      <button>Upload</button>
24    </form>
25  );
26}

#複数のファイル

複数のファイルをアップロードできるようにするには、ファイル入力に multiple 属性を設定する必要があります。フィールドメタデータのエラーが各ファイルのすべてのエラーを含んでいない可能性があることに注意することが重要です。 yup および zod からのエラーは、対応するパスに基づいてマッピングされ、各ファイルのエラーは、配列自体(例: files )ではなく、対応するインデックス(例: files[0] )にマッピングされます。すべてのエラーを表示したい場合は、フィールドメタデータの allErrors プロパティを代わりに使用することを検討できます。

1import { useForm } from '@conform-to/react';
2import { parse } from '@conform-to/zod';
3import { z } from 'zod';
4
5const schema = z.object({
6  files: z
7    .array(
8      z
9        .instanceof(File)
10        .refine((file) => file.size < 1024, 'File size must be less than 1kb'),
11    )
12    .min(1, 'At least 1 file is required')
13    .refine(
14      (files) => files.every((file) => file.size < 1024),
15      'File size must be less than 1kb',
16    ),
17});
18
19function Example() {
20  const [form, fields] = useForm({
21    onValidate({ formData }) {
22      return parseWithZod(formData, { schema });
23    },
24  });
25
26  return (
27    <form method="POST" encType="multipart/form-data" id={form.id}>
28      <div>
29        <label>Mutliple Files</label>
30        <input type="file" name={fields.files.name} multiple />
31        <div>
32          {Object.entries(fields.files.allErrors).flatMap(
33            ([, messages]) => messages,
34          )}
35        </div>
36      </div>
37      <button>Upload</button>
38    </form>
39  );
40}