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?

More than 1 year has passed since last update.

こぼのフロントエンドレビュー帳Advent Calendar 2022

Day 18

【React】react-hook-formを使うなら、zodと組み合わせるといいよ

Posted at

はじめに

という記事を一つ前のアドベントカレンダーで話しましたが、さらに発展して一つ。

react-hook-formを使うのであれば、zodというスキーマ検証ツールを使うといいよ

という話をします。

zodの紹介

zodはTypeScriptのスキーマバリデーションツールです。
直感的に使えるので、ざっとREADMEを読めば使えるようになるかと思います。

TypeScriptファーストというのと、シンプルに使えるという点が気に入って使っています。

スキーマの生成

const User = z.object({
  username: z.string().min(5, { message: "5文字以上入力してください" }),
  email: z.string().email({ message: "正しいメールアドレスを入力してください" }),
});

のようにバリデーションスキーマを作ることができます。

バリデーション

実際にバリデーションをする場合、parseに検証したい値を渡せばできます。

const user = { username: 'qiitan', email: 'sample@sample.com' }
User.parse(user);

parseだとエラーだった場合、exceptionを発生させるため、safeParseというメソッドも用意されてます。

型定義を入手する

zodのスキーマではなく、TypeScriptの型が欲しい場合もあると思いますが、z.inferというtypesにジェネリクスでスキーマを渡すことで実現できます。

type User = z.infer<typeof User>;

react-hook-form × zod

さて、今回の本題である、react-hook-form × zodという構成ですが、react-hook-formの公式プラグインとして提供されています。

import React from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";

const schema = z.object({
  name: z.string(),
  age: z.number()
});

const App = () => {
  const { register, handleSubmit } = useForm({
    resolver: zodResolver(schema)
  });

  return (
    <form onSubmit={handleSubmit(d => console.log(d))}>
      <input {...register("name")} />
      <input {...register("age")} type="number" />
      <input type="submit" />
    </form>
  );
};

このようにzodResolverというプラグインを用いて組み込むことができます。

zodの他にもYup, Zod, Joi, Vest, Ajv など色々用意されてます。
筆者は他をあまり使ったことがないので、他のツールもそれぞれ良いところがあると思いますが、シンプルに使えてTypeScriptファーストなZodが気に入ってます。

なぜreact-hook-form標準のバリデーションではなく、zodと組み合わせるといいのか

A. バリデーションロジックをreact-hook-formから切り離すことができるから

バリデーションロジックというのはとても大切なものです。

react-hook-form標準のバリエーションロジックは、それぞれのフォームを登録する時にオプションとして渡します。

<input
  {...register("test", {
    required: true
  })}
/>

ですが、これにはいくつかの問題があります。

1. ロジックをまとめられる

registerをするのは各コンポーネントになるため、処理が各コンポーネントにばらけます。
該当のコンポーネントに一対一でバリデーションロジックが書かれているというのはそれはそれで都合がいいときもありますが、いくつかの場所で再利用しているコンポーネントだったりすると、追うのが難しくなります。

その点、zodと組み合わせると、useFormするタイミングで全てのバリデーションロジックを流し込むことができるため、一箇所にバリデーションロジックをまとめ上げることができます。

2. 再利用性が上がる

標準のバリエーションだと、フォームと密結合になってしまうため、同じバリデーションを送信前や送信後のサーバーサイドで使いまわしたい場合に使うことができません。

フォームのバリエーションをなんとか掻い潜るみたいな悪いことをする人がいないとは限らないので、サーバーサイドでも検証したかったりします。

zodを用いれば、バリデーションロジックのみ切り離すことができるため、サーバーサイドでも同じzodを用いて検証を行うことができます。

3. テストが書ける

これが一番大きいかもしれません。

標準のバリデーションだと、バリデーションロジックのみ検証したいのにどうしてもフォームの操作(コンポーネントテスト)が必要になります。

zodを用いれば、バリデーションロジックのみ切り出すことができるため、単体テストを書くことができます。

まとめ

react-hook-formを使うなら、zodと組み合わせるといいよ

という話をしました。
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?