0
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?

React Hook Form: Zodを使ってバリデーション

Posted at

React Hook Form と Zod

React Hook Form はフォーム管理管理ライブラリ、
Zodはバリデーションライブラリです。
resolverライブラリを使って、React Hook Form と Zod を統合します。

Zod使用前のコード

import { SubmitHandler, useForm } from "react-hook-form";

// これから変更する点
type FormFields = {
  email: string
  password: string
};

const Form = () => {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
    setError,
  } = useForm<FormFields>(); // これから変更する点

  const onSubmit: SubmitHandler<FormFields> = async (data) => {

    try {
      const response = await fetch("https://example.com/api/login", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(data),
      });

      if (!response.ok) {
        throw new Error("Failed to log in");
      }

      console.log("Login successful");
    } catch (error) {
      setError("root", { message: error.message || "Failed to log in" });
    }
  };
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        type="text"
        // これから変更する点
        {...register("email", {
          required: "Email is required",
          validate: (value) => {
            if (!value.includes("@")) {
              return "Email must include @";
            }
            return undefined;
          },
        })}
      />
      {errors.email && (
        <div>{errors.email.message}</div>
      )}
      <input
        type="text"
        // これから変更する点
        {...register("password", {
          required: "Password is required",
          minLength: {
            value: 8,
            message: "Password must have at least 8 characters",
          },
        })}
      />
      {errors.password && (
        <div>{errors.password.message}</div>
      )}
      <button
        type="submit"
        disabled={isSubmitting}
      >
        {isSubmitting ? "Loading..." : "Submit"}
      </button>
      {errors.root && <div>{errors.root.message}</div>}
    </form>
  );
};

export default Form;

Zod使用後のコード

import { SubmitHandler, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; // resolverのimport
import { z } from "zod"; // zのimport

// スキーマの作成
const schema = z.object({
  email: z
    .string()
    .email("Please enter a valid email address")
    .nonempty("Email is required"),
  password: z
    .string()
    .min(8, "Password must be at least 8 characters")
    .nonempty("Password is required"),
})

// 型はスキーマから推論
type FormFields = z.infer<typeof schema>

const Form = () => {
  // スキーマを渡す
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
    setError,
  } = useForm<FormFields>({
    resolver: zodResolver(schema)
  });

  const onSubmit: SubmitHandler<FormFields> = async (data) => {

    try {
      const response = await fetch("https://example.com/api/login", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(data),
      });

      if (!response.ok) {
        throw new Error("Failed to log in");
      }

      console.log("Login successful");
    } catch (error) {
      setError("root", { message: error.message || "Failed to log in" });
    }
  };
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        type="text"
        // バリデーションはスキーマに移動したので削除
        {...register("email")}
      />
      {errors.email && (
        <div>{errors.email.message}</div>
      )}
      <input
        type="text"
        // バリデーションはスキーマに移動したので削除
        {...register("password")}
      />
      {errors.password && (
        <div>{errors.password.message}</div>
      )}
      <button
        type="submit"
        disabled={isSubmitting}
      >
        {isSubmitting ? "Loading..." : "Submit"}
      </button>
      {errors.root && <div>{errors.root.message}</div>}
    </form>
  );
};

export default Form;

改善した点

改善した点は以下です。

  • スキーマでバリデーションを作成したことによって、1箇所にまとめられた
  • スキーマから型を推論することによって、型を自分で作成する必要がなくなった
  • register部分にバリデーションを書く必要がなくなり、レンダリングの部分がすっきりした
0
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
0
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?