1
1

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 の defaultValues が更新されない問題と解決策

1
Last updated at Posted at 2025-08-19

はじめに

現在ポートフォリオを作成していますが、React Hook Formを使った編集フォームで、「一覧データは更新されているのに、編集ダイアログのフォームには古いデータが表示される」という問題に遭遇しました。

この記事では、その原因と解決策を紹介致します。

バージョンv7.40.0は2023年度の対応なので今更ではありますが、
対応の備忘録として記載させて頂きます。

問題の概要

Next.js の App Router + Server Actions を使った会社管理システムで以下のような現象が発生:

function CompanyList() {
  const companies = await getCompanies();
  
  return (
    <div>
      {companies.map(company => (
        <div key={company.id}>
          <span>{company.companyName}</span> {/* ← 更新されている */}
          <UpsertCompanyDialog 
            type="edit" 
            data={company} // ← このデータも最新
          />
        </div>
      ))}
    </div>
  );
}

// 編集ダイアログ
function UpsertCompanyDialog({ type, data }) {
  const form = useForm({
    defaultValues: data // ← なぜか古いデータのまま...
  });
}

現象

  1. ✅ データベースは正常に更新される
  2. revalidatePath() でサーバーキャッシュも更新される
  3. ✅ 一覧画面には最新データが表示される
  4. 編集フォームだけ古いデータが表示される

原因の解明

ダイアログの場合の問題

// ダイアログの場合
function CompanyList() {
  const companies = getCompanies(); // revalidatePathで更新される
  
  return (
    <div>
      {companies.map(company => (
        // ダイアログコンポーネントは既存のまま(再マウントされない)
        <UpsertCompanyDialog data={company} /> // propsは更新されるが...
      ))}
    </div>
  );
}

React Hook Form の defaultValues は初回マウント時にのみ評価されるため、その後 props が変わっても再評価されません。

つまり:

  • ダイアログ: 既存のコンポーネント = 既存のフォーム = 古い defaultValues

従来の解決策

従来はuseEffectを利用して、値を検知したり、
form.resetを利用して明示的にフォームをリセットする必要がありましたが、
v7.40.0以降のリリースにてvaluesを利用してフォームの値を更新することが可能になりました。

解決策 (v7.40.0以降)

import { useForm } from 'react-hook-form';

export const useCompany = ({ type, data }) => {
  const form = useForm({
    defaultValues: {
      companyName: '',
      domain: '',
    },
    values: type === 'edit' && data 
      ? {
          companyName: data.companyName,
          domain: data.domain,
        }
      : undefined, // 新規作成時は undefined
    resolver: zodResolver(CompanySchema),
  });

  const onSubmit = async (formData) => {
    const result = await (type === 'edit' ? editCompany : addCompany)(formData);
    if (result.success) {
      toast.success('更新が完了しました');
    }
  };

  return { form, onSubmit };
};

めちゃくちゃ便利ですね!

参考リンク


この記事が同じ問題で悩んでいる方の助けになれば幸いです! 🎉

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?