インテグレーション / Remix

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}