💠

Ant Design + react-hook-form + zod

2023/10/24に公開

概要

Ant Designを使用する際にあらかじめ用意されたrulesによるバリデーションではなく, react-hook-formzodを用いたバリデーションを実装する方法を紹介します。

前提

可読性のため, すべて同じページファイルに記載し,3つのステップに分けてコードを掲載していきます。はじめにAnt Designによるシンプルな実装です。公式ドキュメントにあるものから少し変更しました。

import { Button, Form, Input } from 'antd';

const App = () => {
  return (
    <Form>
      <Form.Item<{ email: string }>
        label="メールアドレス"
        name="email"
        rules={[{ required: true }]}
      >
        <Input />
      </Form.Item>
      <Form.Item>
        <Button htmlType="submit">送信</Button>
      </Form.Item>
    </Form>
  );
};

export default App;

rulesrequiredtrueであるため, 入力せずに送信を押すとエラーメッセージが表示されます。

パッケージ追加

次にzodを使用するためのパッケージをインストールします。

  • react-hook-form
  • react-hook-form-antd
  • zod
  • @hookform/resolvers
npm i react-hook-form react-hook-form-antd zod @hookform/resolvers

注意点として, Ant Designを使用する場合はreact-hook-form-antdもインストールする必要があります。

コード変更

スキーマを定義する前にパッケージを追加したことによるコードの変更を行っていきます。

 import { Button, Form, Input } from 'antd';
+import { useForm } from 'react-hook-form';
+import { FormItem } from 'react-hook-form-antd';

 const App = () => {
+  const { control } = useForm();
   return (
     <Form>
-      <Form.Item<{ email: string }>
-        label="メールアドレス"
-        name="email"
-        rules={[{ required: true }]}
-      >
+      <FormItem control={control} name="email">
         <Input />
-      </Form.Item>
+      </FormItem>
-      <Form.Item>
-        <Button htmlType="submit">送信</Button>
+      <Button>送信</Button>
-      </Form.Item>
     </Form>
   );
 };

 export default App;

Ant Designとzodを使用する場合, Form.Item<Values = any>のかわりにFormItemreact-hook-form-antdからインポートします。

スキーマ定義と実装

最後にスキーマを定義します。zodreact-hook-formを使用したことがあれば見慣れた内容かと思われます。詳細な内容はライブラリの公式ドキュメントを参照してください。

+import { zodResolver } from '@hookform/resolvers/zod';
 // 省略
+import z from 'zod';

+const schema = z.object({
+  email: z.string().email(),
+});
+type Schema = z.infer<typeof schema>;

 const App = () => {
-  const { control } = useForm();
+  const { control, register, handleSubmit } = useForm<Schema>({
+    resolver: zodResolver(schema),
+  });
   return (
     <Form>
-      <FormItem control={control} name="email">
+      <FormItem control={control} {...register('email')}>
         <Input />
       </FormItem>
-      <Button>送信</Button>
+      <Button onClick={handleSubmit((data) => alert(data.email))}>
+        送信
+      </Button>
     </Form>
   );
 };

 export default App;

参考

Discussion