⭐
Next.js(App Router) + Zod + Prisma+ React Hook FormでTODOリストを作りました
背景
React Hook Formの良さを体感すべく、React Hook Formを使った時と使わなかった時のTODOリストを実装します。
当記事は、React Hook Formを使った場合の実装します。
GitHubはこちら
1. プロジェクトのセットアップ
npx create-next-app@latest todo-list-next-and-react-hook-form
cd todo-list-next-and-react-hook-form
プロンプトでは以下のように選択してください:
- TypeScript: Yes
- ESLint: Yes
- Tailwind CSS: Yes
- src/ directory: Yes
- App Router: Yes
- Import alias: No
2. 必要なパッケージをインストール
npm install @prisma/client zod
npm install -D prisma
npm install react-hook-form @hookform/resolvers zod
3. Docker Compose ファイルの作成
プロジェクトのルートにdocker-compose.ymlファイルを作成します。
docker-compose.yml
version: '3.8'
services:
db:
image: postgres:13
environment:
POSTGRES_USER: todouser
POSTGRES_PASSWORD: todopassword
POSTGRES_DB: todo_db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
4. PostgreSQL の起動
docker-compose up -d
5. Prismaの初期化
npx prisma init
6. .envファイルを編集
DATABASE_URL="postgresql://todouser:todopassword@localhost:5432/todo_db?schema=public"
7. prisma/schema.prismaファイルを編集
prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Todo {
id Int @id @default(autoincrement())
title String
completed Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
8. データベースのマイグレーションを実行
npx prisma migrate dev --name init
9. next.config.jsファイルを編集してサーバーアクションを有効化
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
},
}
module.exports = nextConfig
10. コードを書く
GitHub参照
それでは、React Hook Formを使わなかった時の実装と比較して違うところを書いていきます。
1. Form用のSchemaが追加される
import { z } from "zod";
export const TodoSchema = z.object({
id: z.number().optional(),
title: z
.string()
.min(1, "Title is required")
.max(100, "Title must be 100 characters or less"),
completed: z.boolean().default(false),
});
// 追加された
export const TodoFormSchema = TodoSchema.omit({ id: true, completed: true });
export type Todo = z.infer<typeof TodoSchema>;
// 追加された
export type TodoFormData = z.infer<typeof TodoFormSchema>;
2. React Hook Formを使用してフォームが実装される
"use client";
import { addTodo } from "@/app/actions";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { TodoFormSchema, TodoFormData } from "@/lib/validate";
export function AddTodoForm() {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<TodoFormData>({
resolver: zodResolver(TodoFormSchema),
});
const onSubmit = async (data: TodoFormData) => {
await addTodo(data);
reset();
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="flex gap-2">
<input
{...register("title")}
placeholder="New todo"
className="flex-grow px-2 py-1 border rounded text-gray-800"
/>
<button
type="submit"
className="px-4 py-1 bg-blue-500 text-white rounded"
>
Add
</button>
{errors.title && (
<p className="text-red-500 text-sm">{errors.title.message}</p>
)}
</form>
);
}
11. アプリケーションの起動
npm run dev
補足
開発が終わったら、Dockerコンテナを停止します。
1. Dockerコンテナの停止
Dockerコンテナを停止したい場合は、以下のコマンドを使用します。
docker-compose down
2. Dockerコンテナの停止して、データを完全に削除したい場合
-vオプションを追加します
docker-compose down -v
まとめ
私が体感したReact Hook Formを使った時と使わなかった時の違いは、以下2つでした。
- React Hook Formは入力中や送信前にzodのバリデーションを行ってくれる
- React Hook Formはエラーの状態管理が自動的に行われる
関連記事
Next.jsを使った開発における勘所を鍛える
React + zod + Bun + PrismaでTODOリストを作りました
Next.js(App Router) + zod + PrismaでTODOリストを作りました
Next.js(App Router) + zod + Prisma+React Hook FormでTODOリストを作りました
GitHub
Discussion