Remix
Remix とインテグレーションしたログインフォームの例です。完全な例は こちら です。
1import { getFormProps, getInputProps, useForm } from '@conform-to/react';
2import { parseWithZod } from '@conform-to/zod';
3import type { ActionArgs } from '@remix-run/node';
4import { json, redirect } from '@remix-run/node';
5import { Form, useActionData } from '@remix-run/react';
6import { z } from 'zod';
7
8const schema = z.object({
9 email: z.string().email(),
10 password: z.string(),
11 remember: z.boolean().optional(),
12});
13
14export async function action({ request }: ActionArgs) {
15 const formData = await request.formData();
16 const submission = parseWithZod(formData, { schema });
17
18 if (submission.status !== 'success') {
19 return json(submission.reply());
20 }
21
22 // ...
23}
24
25export default function Login() {
26 // サーバーから最後に返された送信結果
27 const lastResult = useActionData<typeof action>();
28 const [form, fields] = useForm({
29 // 前回の送信結果を同期
30 lastResult,
31
32 // クライアントでバリデーション・ロジックを再利用する
33 onValidate({ formData }) {
34 return parseWithZod(formData, { schema });
35 },
36
37 // blurイベント発生時にフォームを検証する
38 shouldValidate: 'onBlur',
39 shouldRevalidate: 'onInput',
40 });
41
42 return (
43 <Form method="post" id={form.id} onSubmit={form.onSubmit} noValidate>
44 <div>
45 <label>Email</label>
46 <input
47 type="email"
48 key={fields.email.key}
49 name={fields.email.name}
50 defaultValue={fields.email.initialValue}
51 />
52 <div>{fields.email.errors}</div>
53 </div>
54 <div>
55 <label>Password</label>
56 <input
57 type="password"
58 key={fields.password.key}
59 name={fields.password.name}
60 defaultValue={fields.password.initialValue}
61 />
62 <div>{fields.password.errors}</div>
63 </div>
64 <label>
65 <div>
66 <span>Remember me</span>
67 <input
68 type="checkbox"
69 key={fields.remember.key}
70 name={fields.remember.name}
71 defaultChecked={fields.remember.initialValue === 'on'}
72 />
73 </div>
74 </label>
75 <hr />
76 <button>Login</button>
77 </Form>
78 );
79}