2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js(App Router) + Zod + Prisma+ React Hook FormでTODOリストを作りました

Posted at

背景

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はエラーの状態管理が自動的に行われる
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?