watchとuseWatchの違いと使い分け【Next.js/TypeScript/React Hook Form】

## はじめに

React Hook Formは、Reactでフォームを扱う際に非常に有用なライブラリです。フォームの状態管理を簡素化し、パフォーマンスの最適化も考慮されています。その中でも、フォームの値を監視するためのメソッドとして`watch`と`useWatch`があります。

この記事では、`watch`と`useWatch`の違いと使い分けについて詳しく解説します。具体的なコード例を交えながら、それぞれの特徴や適切な使用シーンを理解していきましょう。


## watchとuseWatchとは

### watch

`watch`は、フォームの値をリアルタイムで監視するための関数です。フォーム全体、特定のフィールド、または複数のフィールドの値を取得できます。

```tsx
const { register, watch } = useForm();

const value = watch(); // フォーム全体の値を取得
const firstName = watch('firstName'); // 特定のフィールドの値を取得
const selectedValues = watch(['firstName', 'lastName']); // 複数のフィールドの値を取得
```

**特徴:**

- **同期的**：`watch`は現在のフォームの状態を即時に返します。
- **再レンダリング**：`watch`自体がコンポーネントの再レンダリングを引き起こさないため、パフォーマンス面で有利です。

### useWatch

`useWatch`は、フォームの値を監視するためのReactフックです。指定したフィールドの値が変化すると、コンポーネントが再レンダリングされます。

```tsx
const { control, register } = useForm();

const firstName = useWatch({
  control,
  name: 'firstName',
});

const selectedValues = useWatch({
  control,
  name: ['firstName', 'lastName'],
});
```

**特徴:**

- **リアクティブ**：指定したフィールドの値が変化すると、コンポーネントが再レンダリングされます。
- **柔軟性**：フォームの状態に応じて動的なUIを構築する際に便利です。


## watchとuseWatchの違い

|            | watch                                                        | useWatch                                              |
| ------------------------- | ------------------------------------------------------------ | ----------------------------------------------------- |
| 戻り値                    | 現在の値を即時に返す                                         | フォームの値を監視し、値が変化すると再レンダリング     |
| 再レンダリングのトリガー  | なし（`useEffect`と組み合わせて手動でトリガー可能）           | 値の変更に応じて自動で再レンダリング                  |
| 主な使用シーン            | 値の即時取得やバリデーション、イベントハンドラでの利用       | コンポーネントの表示・非表示切り替え、動的なUI更新     |


## 実装例

### シナリオ

ユーザーが入力したパスワードの強度をリアルタイムでチェックし、強度に応じてメッセージを表示するフォームを作成します。

### watchを使用した実装

```tsx
import React from 'react';
import { useForm } from 'react-hook-form';

const PasswordForm = () => {
  const { register, watch } = useForm();

  // パスワードの値を即時取得
  const password = watch('password');

  // パスワードの強度を判定する関数
  const getPasswordStrength = (password: string) => {
    if (!password) return '';
    if (password.length > 8) return '強いパスワードです';
    return '弱いパスワードです';
  };

  return (
    <form>
      <input type="password" {...register('password')} placeholder="パスワードを入力" />
      <p>{getPasswordStrength(password)}</p>
    </form>
  );
};

export default PasswordForm;
```

**解説:**

- `watch('password')`でパスワードの値を取得します。
- パスワードの強度を判定し、メッセージを表示します。
- 値の変化に応じて表示を更新するために、コンポーネント全体が再レンダリングされます。

### useWatchを使用した実装

```tsx
import React from 'react';
import { useForm, useWatch } from 'react-hook-form';

const PasswordForm = () => {
  const { control, register } = useForm();

  // useWatchでパスワードの値を監視
  const password = useWatch({
    control,
    name: 'password',
    defaultValue: '',
  });

  // パスワードの強度を判定する関数
  const getPasswordStrength = (password: string) => {
    if (!password) return '';
    if (password.length > 8) return '強いパスワードです';
    return '弱いパスワードです';
  };

  return (
    <form>
      <input type="password" {...register('password')} placeholder="パスワードを入力" />
      <p>{getPasswordStrength(password)}</p>
    </form>
  );
};

export default PasswordForm;
```

**解説:**

- `useWatch`を使用して、`password`フィールドの値を監視します。
- パスワードの値が変化すると、該当部分のみが再レンダリングされます。
- パフォーマンスの最適化に寄与します。


## 適切な使い分け

### watchを使うべき場合

- **即時に値を取得したい場合**：イベントハンドラ内や同期的な処理で値を取得する際に有効です。
- **Form全体のレンダリング**：useFormを呼び出している箇所から再レンダリングされる。


### useWatchを使うべき場合

- **値の変化に応じてUIを更新したい場合**：特定のフィールドの値に依存してコンポーネントを更新する際に有効です。
- **最小限の再レンダリング**：`useWatch`は依存している部分のみを再レンダリングするため、パフォーマンスの最適化につながります。


## 注意点

- **再レンダリングのコスト**：`watch`を使用してフォーム全体を監視すると、コンポーネント全体が再レンダリングされる可能性があります。大量のフィールドがある場合、パフォーマンスに影響を与えることがあります。
- **デフォルト値の設定**：`useWatch`を使用する際、`defaultValue`を明示的に設定しないと`undefined`になる可能性があります。

## まとめ

- `watch`はフォームの値を即時に取得し、同期的な処理に適しています。
- `useWatch`は特定のフィールドを監視し、値の変化に応じてコンポーネントを再レンダリングします。
- パフォーマンスや用途に応じて、これらのメソッドを適切に使い分けることが重要です。

React Hook Formを活用することで、フォームの状態管理がよりシンプルかつ効率的になります。`watch`と`useWatch`の特性を理解し、フォーム開発に役立ててください。


# 最後に

React Hook Formの`watch`と`useWatch`は似ているようで、それぞれ異なる特徴と用途があります。フォームの複雑さや要件に応じて、最適な方法を選択することで、より効率的な開発が可能になります。この記事が、皆さんのフォーム開発の参考になれば幸いです。


# 参考


- [React Hook Form 公式ドキュメント](https://react-hook-form.com/)
- [React Hook Form - watch](https://react-hook-form.com/api/useform/watch)
- [React Hook Form - useWatch](https://react-hook-form.com/api/usewatch)

https://zenn.dev/vertz/articles/97cd4e80b3a24e

https://zenn.dev/frontendflat/articles/8ed7d3d83e8146