😀

React Hook Form watchとgetValuesの使い分け

に公開

結論

値の変化をリアルタイムで監視したいときは、watch()またはuseWatch()を使う。
一時的に値を取得したいだけの時はgetValues()を使う。

また、getValues() は値を取得するだけの関数であり、React の再レンダリングを引き起こしません。
そのため、画面の更新が不要な一時的な処理に使うことで、無駄なレンダリングを避けられ、パフォーマンス面でも有利です

一方で watch()useWatch() は、対象の値が変わると再レンダリングされるため、リアクティブな表示や動的な挙動に向いています。

※watchとuseWatchの違いは過去の記事でまとめています。
React Hook Formのwatch()は多用しないほうがいい

getValuesの具体的な使い道リスト

  1. ボタンクリック時に現在のフォーム値を使いたい(例: 確認表示)
const handleConfirm = () => {
  const values = getValues();
  console.log('確認用データ:', values);
};
  1. サブミット前に追加バリデーション・整形をしたい
const onSubmit = (data) => {
  const allValues = getValues();
  if (allValues.useNickname && !allValues.nickname) {
    alert('ニックネームが必要です');
    return;
  }
  // submit処理
};
  1. 条件によってフォームの一部を上書きしたい
const copyAddress = () => {
  const values = getValues();
  setValue('shippingAddress', values.billingAddress);
};
  1. バリデーション関数内で他フィールドの値を参照したい
register('confirmPassword', {
  validate: (value) =>
    value === getValues('password') || 'パスワードが一致しません',
});
  1. フィルタ機能などで一時的に値を取得して API リクエストを投げる
const handleSearch = () => {
  const filters = getValues();
  fetch(`/api/items?category=${filters.category}&keyword=${filters.keyword}`);
};
  1. useEffect で watch のようにリアクティブにしたくない場合
useEffect(() => {
  const timeout = setTimeout(() => {
    const val = getValues('search');
    doSearch(val);
  }, 500);
  return () => clearTimeout(timeout);
}, []);

watchの具体的な使い道リスト

  1. 選択肢に応じて表示を切り替える(条件分岐)
const selected = watch('type');

return (
  <>
    <select {...register('type')}>
      <option value="email">Email</option>
      <option value="phone">Phone</option>
    </select>

    {selected === 'email' && <input {...register('email')} />}
    {selected === 'phone' && <input {...register('phone')} />}
  </>
);
  1. 入力内容のリアルタイムプレビュー
const name = watch('name');

return (
  <>
    <input {...register('name')} placeholder="名前を入力" />
    <p>こんにちは、{name}さん!</p>
  </>
);
  1. 他フィールドの値によって、バリデーションや制御を変える
const isStudent = watch('isStudent');

useEffect(() => {
  if (isStudent) {
    setValue('schoolName', '');
  }
}, [isStudent]);
  1. フォームのすべての値を監視してデバッグ用に出力
const allValues = watch();

useEffect(() => {
  console.log('現在のフォーム値:', allValues);
}, [allValues]);
  1. ラジオボタン・チェックボックスによる UI の切り替え
const plan = watch('plan');

return (
  <>
    <label><input type="radio" value="basic" {...register('plan')} /> Basic</label>
    <label><input type="radio" value="premium" {...register('plan')} /> Premium</label>

    {plan === 'premium' && <p>プレミアムプランには特典がつきます!</p>}
  </>
);

最後に

今回は主に使い分けをまとめさせていただきました。
今回二つの違いを調べたことをきっかけに、watch()を使うたびに「getValues()でなくてよいのか?」といちいち考えるようになりました。
これまでは実務でReactHookFormを使っていると、めんどくさくなってすべてwatch()を使いがちでしたが、おそらく僕と同じようなエンジニアは結構いると思っているので、この細かい使い分けをするだけでも一段階上のエンジニアになれるのではないかと勝手に思っています。

Discussion