概要
- Remixを採用してみて、非常に開発体験が良い一方で、Nextjsなどに比べると情報量が少ないと感じるケースが多くあります。
- バリデーション実装にZodを使用したいというケースは多いと思いますが、RemixでZodを使用するサンプルコードなどはなかなか見つからず、少し苦労したため、他の人にも役立つように、シンプルなサンプルコードを実装しました。
今回はRemixのaction内(サーバー側での処理)での入力値検証を行っています。こうすることで、より安全かつ開発体験良く、バリデーションを実装することが可能です。
サンプルコード
import { json, type ActionFunctionArgs, redirect } from "@remix-run/node";
import { Form, useActionData, useNavigation } from "@remix-run/react";
import { z } from "zod";
const Schema = z.object({
name: z.string().min(1, { message: "名前は必須です。" }),
job: z.string().min(1, { message: "職業は必須です。" }),
});
export async function action({ request }: ActionFunctionArgs) {
// リクエストからフォームデータを取得して、オブジェクトとして扱えるように変換。
const formDataObject = Object.fromEntries(await request.formData());
// safeParseを使用し、上記オブジェクトを検証。
const validationResult = Schema.safeParse(formDataObject);
if (!validationResult.success)
return json({
validationMessages: validationResult.error.flatten().fieldErrors,
});
// ユーザー登録処理。今回は主題でないので、中身は割愛
await createUser(formDataObject);
return redirect("/users");
}
export default function UsersNew() {
const actionData = useActionData<typeof action>();
const validationMessages = actionData?.validationMessages;
const submitting = useNavigation().state === "submitting";
{/* スタイリングについては主題ではないので、多少雑な部分があります。*/}
return (
<Form
method="post"
className="space-y-2 w-96 mx-auto border-2 p-6 rounded-md shadow-sm"
>
<div>
<div className="flex flex-col gap-1">
<label htmlFor="name" className="font-bold text-sm">
名前
</label>
<input
type="text"
id="name"
name="name"
className="py-1 px-2 border-2 border-gray-300 focus:outline-none focus:border-blue-300 rounded-md"
/>
</div>
{validationMessages?.name && (
<p className="text-sm font-bold text-red-500">
{validationMessages.name[0]}
</p>
)}
</div>
<div>
<div className="flex flex-col gap-1">
<label htmlFor="" className="font-bold text-sm">
職業
</label>
<input
type="text"
id="job"
name="job"
className="py-1 px-2 border-2 border-gray-300 focus:outline-none focus:border-blue-300 rounded-md"
/>
</div>
{validationMessages?.job && (
<p className="text-sm font-bold text-red-500">
{validationMessages.job[0]}
</p>
)}
</div>
<div className="flex">
<button
type="submit"
className="ml-auto bg-blue-500 rounded-lg py-2 px-4 text-white font-bold hover:bg-blue-500/80"
disabled={submitting}
>
{submitting ? "登録中..." : "登録"}
</button>
</div>
</Form>
);
}
実装画面
初期表示
バリデーションエラー(空の状態で登録)
上記から職業だけ入力
終わりに
- 非常に簡素な記事になりましたが、バリデーションはアプリ開発においてほぼ必須かと思いますので、お役に立てると幸いです。