
React Hook Form
- 55 installs
- 2 repo stars
- Updated August 3, 2026
- fandhe-ai/agent-reference-skills
Helps with frontend development tasks.
About
react-hook-form is a Claude Code skill for frontend development. It helps solo builders move faster with AI-assisted coding.
- react-hook-form
- Frontend Development
- AI-coding skill
React Hook Form by the numbers
- 55 all-time installs (skills.sh)
- Ranked #1,255 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/fandhe-ai/agent-reference-skills --skill react-hook-formAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 55 |
|---|---|
| repo stars | ★ 2 |
| Last updated | August 3, 2026 |
| Repository | fandhe-ai/agent-reference-skills ↗ |
What it does
Helps with frontend development tasks.
Files
React Hook Form v7 リファレンス
React Hook Form v7 の全 API ドキュメントを網羅したスキル。 ユーザーのタスクに応じて適切な README.md を読み、そこから個別ファイルへ辿ること。
ディレクトリ構成
skills/react-hook-form/
SKILL.md
references/
get-started/
README.md
api/
README.md
useform.md
usecontroller.md
useformcontext.md
usewatch.md
useformstate.md
usefieldarray.md
uselens.md
createformcontrol.md
useform-register.md
useform-unregister.md
useform-formstate.md
useform-watch.md
useform-subscribe.md
useform-handlesubmit.md
useform-reset.md
useform-resetfield.md
useform-resetdefaultvalues.md
useform-seterror.md
useform-clearerrors.md
useform-setvalue.md
useform-setvalues.md
useform-setfocus.md
useform-getvalues.md
useform-getfieldstate.md
useform-trigger.md
useform-control.md
useform-form.md
controller.md
formprovider.md
watch-component.md
errormessage.md
formstatesubscribe.md
typescript/
README.md
advanced/
README.md
faqs/
README.md
dev-tools/
README.md
samples/
README.md
basic-form.md
schema-validation.md
controlled-component.md
field-array.md
form-provider.md
async-submit.md
watch-conditional-fields.md
reset-after-submit.md
typescript-typed-form.md
scripts/
README.md
install.md
develop.md探索手順
タスクからカテゴリを引き、カテゴリの README.md で目的のページを特定する:
1. 下記マッピング表でタスクに対応するカテゴリを探す 2. そのカテゴリの references/{category}/README.md を参照して目的のページを特定する 3. 該当ページの .md を Read して詳細を確認する
タスク → カテゴリ マッピング
| タスク | カテゴリ | 参照 README |
|---|---|---|
| インストール、基本的なフォーム作成、バリデーションルール、スキーマ統合 | get-started | references/get-started/README.md |
| useForm, register, handleSubmit, reset, watch, setValue, getValues | api | references/api/README.md |
| Controller, useController, FormProvider, useFormContext | api | references/api/README.md |
| useFieldArray (動的フィールド)、useLens、createFormControl | api | references/api/README.md |
| useWatch, useFormState, subscribe, formState | api | references/api/README.md |
| 型定義、ジェネリクス、FieldPath, Resolver 型 | typescript | references/typescript/README.md |
| アクセシビリティ、ウィザードフォーム、テスト、仮想リスト | advanced | references/advanced/README.md |
| パフォーマンス、クラスコンポーネント、watch vs getValues、条件付きレンダリング | faqs | references/faqs/README.md |
| DevTools のインストール・デバッグ | dev-tools | references/dev-tools/README.md |
| 典型的な使い方を知りたい、実装例を参照したい | samples | samples/README.md |
| インストール・開発環境セットアップのコマンドを知りたい | scripts | scripts/README.md |
Advanced
| Name | Description | Path |
|---|
Controller
制御コンポーネント(React-Select、AntD、MUI など)をラップするためのコンポーネント。useController のコンポーネント版であり、render prop パターンでフィールドのバインディングを提供する。
シグネチャ
<Controller
name={string} // 必須
control={Control}
render={Function} // 必須
rules={Object}
defaultValue={unknown}
disabled={boolean}
shouldUnregister={boolean}
exact={boolean}
/>Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
name | FieldPath | はい | - | フィールドの一意な名前 |
control | Control | いいえ | - | useForm の制御オブジェクト。FormProvider 使用時は省略可 |
render | Function | はい | - | React 要素を返す render 関数。field, fieldState, formState を引数に受け取る |
rules | Object | いいえ | - | バリデーションルール(required, min, max, minLength, maxLength, pattern, validate) |
defaultValue | unknown | いいえ | - | フィールドのデフォルト値。undefined は不可 |
disabled | boolean | いいえ | false | 入力を無効化する。送信データから値が除外される |
shouldUnregister | boolean | いいえ | false | アンマウント時にフィールドを登録解除する。useFieldArray との併用は避ける |
exact | boolean | いいえ | false | フィールド名の購読で完全一致を有効にする |
render 関数の引数
field オブジェクト
| Name | Type | Description |
|---|---|---|
onChange | (value: any) => void | 値をフォーム状態に送信する。値に undefined は使用不可 |
onBlur | () => void | インタラクション/タッチイベントを報告する |
value | unknown | 制御コンポーネントの現在の値 |
disabled | boolean | 入力の無効状態 |
name | string | 登録されたフィールド名 |
ref | React.Ref | エラー時のフォーカス管理用リファレンス |
fieldState オブジェクト
| Name | Type | Description |
|---|---|---|
invalid | boolean | バリデーションの状態 |
isTouched | boolean | ユーザーがフィールドに触れたかどうか |
isDirty | boolean | フィールドが変更されたかどうか |
error | object | フィールド固有のエラー情報 |
formState オブジェクト
| Name | Type | Description |
|---|---|---|
isDirty | boolean | フォーム全体の変更状態 |
dirtyFields | object | 変更されたフィールドの一覧 |
touchedFields | object | タッチされたフィールドの一覧 |
defaultValues | object | フォームのデフォルト値 |
isSubmitted | boolean | フォームが送信されたかどうか |
isSubmitSuccessful | boolean | 送信が成功したかどうか |
isSubmitting | boolean | 送信中かどうか |
isLoading | boolean | 非同期 defaultValues のロード中かどうか |
submitCount | number | 送信回数 |
isValid | boolean | バリデーションエラーがないかどうか |
isValidating | boolean | バリデーション実行中かどうか |
errors | object | フィールドエラーメッセージ |
コード例
Web(React)での使用
import { useForm, Controller } from "react-hook-form";
import ReactDatePicker from "react-datepicker";
function App() {
const { handleSubmit, control } = useForm({
defaultValues: { dateField: new Date() },
});
return (
<form onSubmit={handleSubmit(console.log)}>
<Controller
control={control}
name="dateField"
render={({ field: { onChange, onBlur, value } }) => (
<ReactDatePicker
onChange={onChange}
onBlur={onBlur}
selected={value}
/>
)}
/>
<button type="submit">送信</button>
</form>
);
}React Native での使用
import { useForm, Controller } from "react-hook-form";
import { TextInput, Button, View } from "react-native";
function App() {
const { handleSubmit, control } = useForm({
defaultValues: { firstName: "" },
});
return (
<View>
<Controller
control={control}
name="firstName"
rules={{ required: true }}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
onChangeText={onChange}
onBlur={onBlur}
value={value}
/>
)}
/>
<Button title="送信" onPress={handleSubmit(console.log)} />
</View>
);
}バリデーション付き
<Controller
control={control}
name="email"
rules={{
required: "メールアドレスは必須です",
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: "有効なメールアドレスを入力してください",
},
}}
render={({ field, fieldState: { error } }) => (
<div>
<input {...field} />
{error && <span>{error.message}</span>}
</div>
)}
/>重要なルール
1. 二重登録の禁止: Controller と register() を同じフィールドに使用しないこと。Controller が内部でフィールド登録を行う。 2. 値のクリアには `null` か空文字を使用: onChange に undefined を渡してはならない。値をクリアする場合は null または "" を使用する。 3. defaultValues の設定: useForm の defaultValues でデフォルト値を一元管理することを推奨。dirty 状態の比較基準となる。 4. shouldUnregister と useFieldArray: shouldUnregister を useFieldArray と併用すると予期しない動作になるため避けること。
createFormControl
React Context を使わずにフォーム状態を作成する関数。v7.55.0 以降で利用可能。FormProvider でラップせずにフォームメソッドを直接使用でき、subscribe でコンポーネントの再レンダリングなしにフォーム状態を購読できる。
バージョン要件
- v7.55.0+(オプション機能)
シグネチャ
createFormControl<TFieldValues>(
props?: UseFormProps<TFieldValues>
): CreateFormControlReturn<TFieldValues>引数
| Name | Type | Required | Description |
|---|---|---|---|
props | UseFormProps | いいえ | useForm と同じ設定オプション(defaultValues, mode, resolver など) |
Return
| Name | Type | Description |
|---|---|---|
formControl | Object | useForm フックに統合するための制御オブジェクト |
control | Object | useController, useFormState, useWatch で使用する制御オブジェクト |
subscribe | Function | 再レンダリングなしでフォーム状態の変更を購読する |
register | Function | フィールドを登録する |
unregister | Function | フィールドの登録を解除する |
handleSubmit | Function | フォーム送信を処理する |
reset | Function | フォーム値をリセットする |
resetField | Function | 個別フィールドをリセットする |
setError | Function | エラーを手動で設定する |
clearErrors | Function | バリデーションエラーをクリアする |
setValue | Function | フィールド値を更新する |
setFocus | Function | フィールドにフォーカスする |
getValues | Function | 現在の値を取得する |
getFieldState | Function | フィールドの状態を取得する |
trigger | Function | バリデーションを手動で実行する |
watch | Function | フィールド値の変更を監視する |
formState | Object | フォームの状態情報 |
コード例
基本的な使い方
import { createFormControl } from "react-hook-form";
// フォーム制御をコンポーネント外で作成
const {
register,
handleSubmit,
control,
formState,
subscribe,
} = createFormControl({
defaultValues: {
firstName: "",
lastName: "",
email: "",
},
});
function App() {
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<input {...register("email")} />
<button type="submit">送信</button>
</form>
);
}subscribe による再レンダリングなしの購読
const { register, handleSubmit, subscribe } = createFormControl({
defaultValues: { name: "" },
});
// 再レンダリングなしでフォーム状態を購読
const unsubscribe = subscribe({
formState: {
// 購読したい状態を指定
isDirty: true,
errors: true,
},
callback: (formState) => {
// フォーム状態が変更されたときに呼ばれる
console.log("isDirty:", formState.isDirty);
console.log("errors:", formState.errors);
// DOM を直接操作するなど、React 外の処理に有用
document.getElementById("status").textContent = formState.isDirty
? "変更あり"
: "変更なし";
},
});
// 不要になったら購読解除
unsubscribe();useForm の formControl と統合
import { useForm, createFormControl } from "react-hook-form";
const { formControl } = createFormControl({
defaultValues: { name: "" },
});
function App() {
// formControl を useForm に渡して統合
const { register, handleSubmit } = useForm({
formControl,
});
return (
<form onSubmit={handleSubmit(console.log)}>
<input {...register("name")} />
<button type="submit">送信</button>
</form>
);
}useController との併用
import { useController } from "react-hook-form";
const { control, handleSubmit } = createFormControl({
defaultValues: { date: new Date() },
});
function DateField() {
const { field } = useController({
control,
name: "date",
});
return (
<DatePicker
value={field.value}
onChange={field.onChange}
/>
);
}重要なルール
1. Context API か createFormControl のどちらかを使う: 両方を同時に使用しないこと。createFormControl を使用する場合は FormProvider でラップしない。
2. FormProvider は不要: createFormControl はコンポーネントツリー外でフォーム状態を作成するため、FormProvider によるラップが不要。メソッドを直接インポートして使用できる。
3. subscribe の用途: subscribe はコンポーネントの再レンダリングをトリガーせずにフォーム状態の変更を購読する。パフォーマンスが重要な場面や、DOM 直接操作、外部ライブラリとの統合に適している。
4. オプション機能: createFormControl は完全にオプションであり、従来の useForm + useFormContext パターンの代替手段として提供される。
5. 非 React 環境: React コンポーネント外でフォーム状態が必要な場合(例: ユーティリティ関数、外部ライブラリ統合)に特に有用。
ErrorMessage
React Hook Form のエラーメッセージを表示するためのコンポーネント。@hookform/error-message パッケージとして提供される。
インストール
npm install @hookform/error-messageシグネチャ
import { ErrorMessage } from "@hookform/error-message";
<ErrorMessage
name={string} // 必須
errors={object}
message={string | ReactElement}
as={ReactElementType | string}
render={Function}
/>Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | はい | - | 対象のフォームフィールド名 |
errors | object | いいえ | - | useForm の formState.errors オブジェクト。FormProvider 使用時は省略可 |
message | `string \ | React.ReactElement` | いいえ | - |
as | `React.ElementType \ | string` | いいえ | - |
render | Function | いいえ | - | エラー表示をカスタマイズする render 関数 |
コード例
基本的な使い方(単一エラー)
import { useForm } from "react-hook-form";
import { ErrorMessage } from "@hookform/error-message";
function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
defaultValues: { name: "" },
});
return (
<form onSubmit={handleSubmit(console.log)}>
<input
{...register("name", { required: "名前は必須です" })}
/>
<ErrorMessage errors={errors} name="name" />
<button type="submit">送信</button>
</form>
);
}render prop でカスタム表示
<ErrorMessage
errors={errors}
name="email"
render={({ message }) => <p className="error">{message}</p>}
/>as prop でラッパー要素を指定
<ErrorMessage
errors={errors}
name="email"
as="span"
/>message prop でインラインメッセージ
<input {...register("name", { required: true })} />
<ErrorMessage
errors={errors}
name="name"
message="このフィールドは必須です"
/>複数エラーモード(criteriaMode: "all")
useForm の criteriaMode を "all" に設定すると、1 つのフィールドに対する複数のバリデーションエラーを同時に表示できる。
import { useForm } from "react-hook-form";
import { ErrorMessage } from "@hookform/error-message";
function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
criteriaMode: "all", // 全エラーを収集
});
return (
<form onSubmit={handleSubmit(console.log)}>
<input
{...register("password", {
required: "パスワードは必須です",
minLength: {
value: 8,
message: "8文字以上で入力してください",
},
pattern: {
value: /[A-Z]/,
message: "大文字を1文字以上含めてください",
},
})}
/>
<ErrorMessage
errors={errors}
name="password"
render={({ messages }) =>
messages &&
Object.entries(messages).map(([type, message]) => (
<p key={type} className="error">
{message}
</p>
))
}
/>
<button type="submit">送信</button>
</form>
);
}重要なルール
1. criteriaMode の設定: 複数エラーを同時表示するには useForm で criteriaMode: "all" を設定する必要がある。デフォルトの "firstError" では最初のエラーのみ返される。 2. render の引数: 単一エラーモードでは { message } を受け取り、複数エラーモードでは { messages } オブジェクトを受け取る。messages は { [validationType]: message } の形式。 3. FormProvider との併用: FormProvider 使用時は errors prop を省略できる。コンテキストから自動的にエラー情報を取得する。 4. エラーが存在しない場合: 対象フィールドにエラーがない場合、コンポーネントは何もレンダリングしない。
FormProvider
useForm の全メソッドを React Context 経由で子コンポーネントに配信するプロバイダーコンポーネント。深くネストされたコンポーネントで useFormContext を使ってフォームメソッドにアクセスするために使用する。
シグネチャ
<FormProvider {...methods}>
{children}
</FormProvider>Props
| Name | Type | Required | Description |
|---|---|---|---|
...props | UseFormReturn | はい | useForm() が返す全メソッドをスプレッド演算子で渡す |
配信されるメソッド
FormProvider 経由で子コンポーネントに提供されるメソッド一覧:
| Name | Description |
|---|---|
register | フィールドを登録する |
unregister | フィールドの登録を解除する |
formState | フォームの状態情報 |
watch | フィールド値の変更を監視する |
handleSubmit | フォーム送信を処理する |
reset | フォーム値をリセットする |
resetField | 個別フィールドをリセットする |
setError | エラーを手動で設定する |
clearErrors | バリデーションエラーをクリアする |
setValue | フィールド値を更新する |
setFocus | フィールドにフォーカスする |
getValues | 現在の値を取得する |
trigger | バリデーションを手動で実行する |
control | フォーム制御オブジェクト |
コード例
基本的な使い方
import { useForm, FormProvider, useFormContext } from "react-hook-form";
function App() {
const methods = useForm({
defaultValues: {
firstName: "",
lastName: "",
email: "",
},
});
const onSubmit = (data) => console.log(data);
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<PersonalInfo />
<ContactInfo />
<button type="submit">送信</button>
</form>
</FormProvider>
);
}
function PersonalInfo() {
const { register } = useFormContext();
return (
<div>
<input {...register("firstName")} placeholder="名前" />
<input {...register("lastName")} placeholder="姓" />
</div>
);
}
function ContactInfo() {
const { register } = useFormContext();
return <input {...register("email")} placeholder="メール" />;
}handleSubmit の使用
function App() {
const methods = useForm();
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit((data) => console.log(data))}>
<NestedFields />
<SubmitButton />
</form>
</FormProvider>
);
}
function SubmitButton() {
const { formState: { isSubmitting } } = useFormContext();
return (
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? "送信中..." : "送信"}
</button>
);
}重要なルール
1. スプレッド演算子で全メソッドを渡す: useForm の返り値を {...methods} でスプレッドして渡すこと。個別のプロパティだけを渡すと useFormContext が正しく動作しない。
// OK
<FormProvider {...methods}>
// NG: 個別に渡さない
<FormProvider control={methods.control} register={methods.register}>2. ネストした FormProvider は避ける: 複数の FormProvider をネストすると、コンテキストの競合が発生する。1 つのフォームには 1 つの FormProvider を使用する。
// NG: ネストしない
<FormProvider {...methodsA}>
<FormProvider {...methodsB}>
{/* コンテキスト競合 */}
</FormProvider>
</FormProvider>3. useEffect 依存配列の注意: FormProvider から取得したメソッドオブジェクト全体を useEffect の依存配列に入れないこと。必要な個別メソッド(例: reset)のみを指定する。
FormStateSubscribe
useFormState フックのコンポーネント版。render prop パターンを使い、JSX 内で宣言的にフォーム状態を購読できる。購読したフィールドの状態が変更された時のみ再レンダリングされる。
シグネチャ
<FormStateSubscribe
control={Control}
name={string | string[]} // 必須
disabled={boolean}
exact={boolean}
render={Function} // 必須
/>Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
control | Control | いいえ | - | useForm の制御オブジェクト。FormProvider 使用時は省略可 |
name | `string \ | string[]` | はい | - |
disabled | boolean | いいえ | false | 購読を無効化する |
exact | boolean | いいえ | false | フィールド名の完全一致を有効にする |
render | Function | はい | - | フォーム状態を受け取り React 要素を返す render 関数。状態変更時に再実行される |
render 関数の引数
render 関数は formState オブジェクトを受け取る。
| Name | Type | Description |
|---|---|---|
isDirty | boolean | フォーム全体の変更状態 |
dirtyFields | object | 変更されたフィールドの一覧 |
touchedFields | object | タッチされたフィールドの一覧 |
defaultValues | object | 初期値 |
isSubmitted | boolean | フォームが送信されたかどうか |
isSubmitSuccessful | boolean | 送信が成功したかどうか |
isSubmitting | boolean | 送信中かどうか |
isLoading | boolean | 非同期 defaultValues のロード中かどうか |
submitCount | number | 送信回数 |
isValid | boolean | バリデーションエラーがないかどうか |
isValidating | boolean | バリデーション実行中かどうか |
validatingFields | object | 非同期バリデーション中のフィールド |
errors | object | フィールドエラーメッセージ |
disabled | boolean | フォームが無効化されているかどうか |
コード例
基本的な使い方
import { useForm, FormStateSubscribe } from "react-hook-form";
function App() {
const { register, control } = useForm({
defaultValues: { foo: "", bar: "" },
});
return (
<form>
<input {...register("foo", { required: "必須です" })} />
<input {...register("bar")} />
<FormStateSubscribe
control={control}
name="foo"
render={({ errors }) => (
<span>{errors.foo?.message}</span>
)}
/>
</form>
);
}送信状態の表示
<FormStateSubscribe
control={control}
name={["firstName", "lastName"]}
render={({ isSubmitting, isValid }) => (
<button type="submit" disabled={isSubmitting || !isValid}>
{isSubmitting ? "送信中..." : "送信"}
</button>
)}
/>dirty 状態の表示
<FormStateSubscribe
control={control}
name="email"
exact={true}
render={({ dirtyFields, errors }) => (
<div>
{dirtyFields.email && <span>変更あり</span>}
{errors.email && <span className="error">{errors.email.message}</span>}
</div>
)}
/>FormProvider との併用
import { useForm, FormProvider, FormStateSubscribe } from "react-hook-form";
function App() {
const methods = useForm();
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(console.log)}>
<input {...methods.register("name")} />
<StatusDisplay />
</form>
</FormProvider>
);
}
function StatusDisplay() {
// FormProvider 内では control 不要
return (
<FormStateSubscribe
name="name"
render={({ isDirty, errors }) => (
<div>
{isDirty && <p>フォームが変更されています</p>}
{errors.name && <p>{errors.name.message}</p>}
</div>
)}
/>
);
}重要なルール
1. render prop は必須: render 関数は必ず指定する。フォーム状態オブジェクトを引数として受け取り、React 要素を返す。 2. 選択的な再レンダリング: 指定したフィールドの状態が変更された時のみ再レンダリングされるため、パフォーマンスに優れる。 3. useFormState との使い分け: フックが使えない場面や、JSX 内で宣言的に状態を表示したい場合に FormStateSubscribe が適している。ロジック処理が必要な場合は useFormState を使用する。 4. exact の活用: exact: true を指定すると、指定したフィールド名に完全一致する状態変更のみで再レンダリングがトリガーされる。ネストされたフィールド名がある場合に有用。
API
| Name | Description | Path |
|---|---|---|
| Controller | 制御コンポーネント(React-Select、AntD、MUI など)をラップするためのコンポーネント。 | controller.md |
| createFormControl | React Context を使わずにフォーム状態を作成する関数。 | createformcontrol.md |
| ErrorMessage | React Hook Form のエラーメッセージを表示するためのコンポーネント。 | errormessage.md |
| FormProvider | useForm の全メソッドを React Context 経由で子コンポーネントに配信するプロバイダーコンポーネント。 | formprovider.md |
| FormStateSubscribe | useFormState フックのコンポーネント版。 | formstatesubscribe.md |
| useController | 制御コンポーネント(React-Select、AntD、MUI など)を React Hook Form と統合するためのカスタムフック。 | usecontroller.md |
| useFieldArray | 動的なフォームフィールド(追加・削除・並べ替え)を管理するためのカスタムフック。 | usefieldarray.md |
| useForm | useForm は React Hook Form の中核となるカスタムフックで、フォーム全体の管理を担う。 | useform.md |
| useForm — clearErrors | clearErrors メソッドはフォームのエラーをクリアする。 | useform-clearerrors.md |
| useForm — control | control はフォームの内部制御を管理するオブジェクトで、Controller、useWatch、useFormState、useFieldArray などのコンポーネントやフックに渡して使用する。 | useform-control.md |
| useForm — Form | Form コンポーネント(Beta)はフォーム送信を管理するラッパーコンポーネントで、標準の HTML form 要素と密接に連携する。 | useform-form.md |
| useForm — formState | formState はフォーム全体の状態情報を格納するオブジェクトで、ユーザーの操作状況やバリデーション結果を追跡する。 | useform-formstate.md |
| useForm — getFieldState | getFieldState メソッドは個別フィールドの状態(dirty, touched, エラー)を取得する。 | useform-getfieldstate.md |
| useForm — getValues | getValues メソッドはフォームの値を取得する。 | useform-getvalues.md |
| useForm — handleSubmit | handleSubmit メソッドはフォーム送信を処理する。 | useform-handlesubmit.md |
| useForm — register | register メソッドは input 要素をフォームに登録し、バリデーションルールを適用する。 | useform-register.md |
| useForm — reset | reset メソッドはフォーム全体の状態(値、エラー、dirty 状態など)をリセットする。 | useform-reset.md |
| useForm — resetDefaultValues | resetDefaultValues メソッドはフォームのデフォルト値を更新し、それに伴い dirty/valid 状態を再計算する。 | useform-resetdefaultvalues.md |
| useForm — resetField | resetField メソッドは個別のフィールドの状態と値をリセットする。 | useform-resetfield.md |
| useForm — setError | setError メソッドはフィールドに手動でエラーを設定する。 | useform-seterror.md |
| useForm — setFocus | setFocus メソッドは登録済みの input フィールドにプログラム的にフォーカスを設定する。 | useform-setfocus.md |
| useForm — setValue | setValue メソッドは登録済みフィールドの値をプログラム的に設定する。 | useform-setvalue.md |
| useForm — setValues | setValues メソッドは複数のフォームフィールドの値を一括で更新する。 | useform-setvalues.md |
| useForm — subscribe | subscribe メソッドは、コンポーネントの再レンダリングなしにフォーム状態の変更を購読する。 | useform-subscribe.md |
| useForm — trigger | trigger メソッドはバリデーションを手動で実行する。 | useform-trigger.md |
| useForm — unregister | unregister メソッドは、登録済みの input フィールドの登録を解除し、対応するバリデーションルールと値を削除する。 | useform-unregister.md |
| useForm — watch | watch メソッドは指定したフィールドの値の変更を監視し、条件付きレンダリングや値の表示に使用する。 | useform-watch.md |
| useFormContext | 深くネストされたコンポーネント構造で、props のバケツリレー(prop drilling)を避けるためのカスタムフック。 | useformcontext.md |
| useFormState | フォーム状態を購読するためのカスタムフック。 | useformstate.md |
| useLens | 型安全にネストされたフォームデータを操作するためのレンズ(Lens)パターンのフック。 | uselens.md |
| useWatch | フォームフィールドの値を購読し、変更を検知するためのカスタムフック。 | usewatch.md |
| Watch | useWatch フックのコンポーネント版。 | watch-component.md |
useController
制御コンポーネント(React-Select、AntD、MUI など)を React Hook Form と統合するためのカスタムフック。register が使えない外部コンポーネントに対して、フォーム状態の接続を提供する。
シグネチャ
useController(props?: UseControllerProps): {
field: UseControllerReturn['field'];
fieldState: UseControllerReturn['fieldState'];
formState: UseControllerReturn['formState'];
}Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
name | FieldPath | はい | - | フィールドの一意な名前 |
control | Control | いいえ | - | useForm から取得する制御オブジェクト。FormProvider 使用時は省略可 |
rules | Object | いいえ | - | バリデーションルール(required, min, max, minLength, maxLength, pattern, validate) |
shouldUnregister | boolean | いいえ | false | アンマウント時にフィールドを登録解除し、defaultValues も削除する |
disabled | boolean | いいえ | false | 入力を無効化する。無効時は送信データから値が除外される |
defaultValue | unknown | いいえ | - | フィールドのデフォルト値。undefined は不可。フィールドレベルまたはフォームレベルで設定 |
exact | boolean | いいえ | false | フィールド名の購読で完全一致を有効にする |
Return
field オブジェクト
| Name | Type | Description |
|---|---|---|
onChange | (value: any) => void | 入力値をフォーム状態に送信する |
onBlur | () => void | 入力のインタラクション(タッチ)を報告する |
value | unknown | 制御コンポーネントの現在の値 |
name | string | 登録されたフィールド名 |
ref | React.Ref | フォーカス管理のためのリファレンス(エラー時のフォーカス移動に使用) |
disabled | boolean | 入力の無効状態 |
fieldState オブジェクト
| Name | Type | Description |
|---|---|---|
invalid | boolean | フィールドのバリデーション状態(エラーがあれば true) |
isTouched | boolean | ユーザーがフィールドに触れたかどうか |
isDirty | boolean | フィールドが変更されたかどうか |
error | object | フィールド固有のエラー情報 |
formState オブジェクト
| Name | Type | Description |
|---|---|---|
isDirty | boolean | フォーム全体の変更状態 |
dirtyFields | object | 変更されたフィールドの一覧 |
touchedFields | object | タッチされたフィールドの一覧 |
defaultValues | object | フォームのデフォルト値 |
isSubmitted | boolean | フォームが送信されたかどうか |
isSubmitSuccessful | boolean | 送信が成功したかどうか |
isSubmitting | boolean | 送信中かどうか |
isLoading | boolean | 非同期 defaultValues のロード中かどうか |
submitCount | number | 送信回数 |
isValid | boolean | バリデーションエラーがないかどうか |
isValidating | boolean | バリデーション実行中かどうか |
validatingFields | object | 非同期バリデーション中のフィールド |
errors | object | フィールドエラーメッセージ |
disabled | boolean | フォームが無効化されているかどうか |
コード例
基本的な使い方
import { useController, useForm } from "react-hook-form";
function TextField({ name, control, rules }) {
const {
field,
fieldState: { invalid, error },
} = useController({
name,
control,
rules: { required: true },
});
return (
<div>
<input
onChange={field.onChange}
onBlur={field.onBlur}
value={field.value}
name={field.name}
ref={field.ref}
/>
{invalid && <p>{error?.message}</p>}
</div>
);
}
function App() {
const { handleSubmit, control } = useForm({
defaultValues: { firstName: "" },
});
return (
<form onSubmit={handleSubmit(console.log)}>
<TextField name="firstName" control={control} rules={{ required: true }} />
<button type="submit">送信</button>
</form>
);
}チェックボックス(配列値)パターン
function Checkboxes({ name, control, options }) {
const { field } = useController({ control, name });
const [value, setValue] = useState(field.value || []);
return (
<>
{options.map((option) => (
<label key={option}>
<input
type="checkbox"
value={option}
checked={value.includes(option)}
onChange={(e) => {
const newValue = e.target.checked
? [...value, option]
: value.filter((v) => v !== option);
setValue(newValue);
field.onChange(newValue);
}}
/>
{option}
</label>
))}
</>
);
}重要なルール
1. 二重登録の禁止: {...field} と {...register()} を同じフィールドに同時使用しないこと。useController がフィールド登録を管理する。 2. 単一インスタンス: 1 つのコンポーネントに対して 1 つの useController を使用する。複数必要な場合はリネームする。 3. defaultValue に `undefined` は不可: defaultValue には undefined を使用できない。フォームレベルの defaultValues で設定すること。 4. dirty 状態の追跡: isDirty を正確に追跡するには、フォームレベルで defaultValues を設定する必要がある。 5. ローカル状態との併用: useState と組み合わせて UI 状態を管理できる(上記チェックボックス例を参照)。
useFieldArray
動的なフォームフィールド(追加・削除・並べ替え)を管理するためのカスタムフック。パフォーマンスとユーザー体験を最適化した配列操作を提供する。
シグネチャ
useFieldArray(props: UseFieldArrayProps): UseFieldArrayReturnProps
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | はい | - | フィールド配列の識別子。動的な名前はサポートしない |
control | Control | いいえ | - | useForm の制御オブジェクト。FormProvider 使用時は省略可 |
shouldUnregister | boolean | いいえ | - | アンマウント時にフィールド配列の登録を解除する |
keyName | string | いいえ | "id" | 自動生成される識別子の属性名(非推奨) |
rules | Object | いいえ | - | 組み込みバリデーションルール: required, minLength, maxLength, validate |
Return
| Name | Type | Description |
|---|---|---|
fields | object[] & { id: string } | defaultValue と一意な id を含むフィールド配列 |
append | `(obj: object \ | object[], focusOptions?) => void` |
prepend | `(obj: object \ | object[], focusOptions?) => void` |
insert | `(index: number, value: object \ | object[], focusOptions?) => void` |
swap | (from: number, to: number) => void | 2 つのフィールドの位置を入れ替える |
move | (from: number, to: number) => void | フィールドを別の位置に移動する |
update | (index: number, obj: object) => void | 指定位置のフィールドを置き換える。コンポーネントが再マウントされる |
replace | (obj: object[]) => void | フィールド配列全体を置き換える |
remove | `(index?: number \ | number[]) => void` |
コード例
基本的な使い方
import { useForm, useFieldArray } from "react-hook-form";
function App() {
const { register, control, handleSubmit } = useForm({
defaultValues: {
items: [{ name: "" }],
},
});
const { fields, append, remove } = useFieldArray({
control,
name: "items",
});
return (
<form onSubmit={handleSubmit(console.log)}>
{fields.map((field, index) => (
<div key={field.id}>
<input {...register(`items.${index}.name`)} />
<button type="button" onClick={() => remove(index)}>
削除
</button>
</div>
))}
<button type="button" onClick={() => append({ name: "" })}>
追加
</button>
<button type="submit">送信</button>
</form>
);
}ネストされたフィールド配列
function NestedFieldArray({ nestIndex, control, register }) {
const { fields, append, remove } = useFieldArray({
control,
name: `items.${nestIndex}.subItems`,
});
return (
<div>
{fields.map((field, index) => (
<div key={field.id}>
<input
{...register(`items.${nestIndex}.subItems.${index}.value`)}
/>
<button type="button" onClick={() => remove(index)}>
削除
</button>
</div>
))}
<button type="button" onClick={() => append({ value: "" })}>
サブアイテム追加
</button>
</div>
);
}バリデーション付き
const { fields, append } = useFieldArray({
control,
name: "items",
rules: {
required: "最低1つのアイテムが必要です",
minLength: {
value: 1,
message: "最低1つのアイテムが必要です",
},
maxLength: {
value: 10,
message: "アイテムは10個までです",
},
},
});操作の組み合わせ
// 複数のフィールドを一括追加
append([{ name: "アイテム1" }, { name: "アイテム2" }]);
// フィールドの入れ替え
swap(0, 1);
// フィールドの移動
move(2, 0); // index 2 を index 0 に移動
// 指定位置に挿入
insert(1, { name: "挿入アイテム" });
// 特定のフィールドを更新
update(0, { name: "更新された値" });
// フィールド配列全体を置き換え
replace([{ name: "新アイテム1" }, { name: "新アイテム2" }]);
// 複数のフィールドを削除
remove([0, 2]); // index 0 と 2 を削除
// 全フィールドを削除
remove();重要なルール
1. key には `field.id` を使用する: 配列の index ではなく、field.id を React の key に使用すること。
// OK
{fields.map((field, index) => (
<div key={field.id}>...</div>
))}
// NG: index を key に使わない
{fields.map((field, index) => (
<div key={index}>...</div>
))}2. defaultValues の設定が必須: useForm で配列フィールドの defaultValues を設定する必要がある。
const { control } = useForm({
defaultValues: {
items: [{ name: "" }], // 必須
},
});3. append/prepend/insert/update には完全なオブジェクトを渡す: 全てのプロパティを含むオブジェクトを渡すこと。空オブジェクトや部分的なデータは不可。
// OK
append({ name: "", email: "" });
// NG: 空オブジェクト
append({});4. 複数操作は useEffect 内で: remove などのアクションは 2 回目のレンダリング後に実行されるため、複数の操作を順次実行する場合は useEffect 内で行う。
// NG: onClick 内で複数操作をスタックしない
onClick={() => {
remove(0);
remove(1); // 意図通りに動作しない
}}
// OK: useEffect 内で
useEffect(() => {
remove(0);
}, [condition]);5. 1 つの名前に 1 つの useFieldArray: 同じフィールド名に対して複数の useFieldArray を使用しないこと。
6. フラット配列と循環参照は非サポート: フィールド配列はオブジェクトの配列である必要がある。フラットな値の配列(string[] など)や循環参照はサポートされない。
7. TypeScript での型アサーション: ネストされた配列のパスは as const でキャストする。
{...register(`items.${index}.name` as const)}useForm — clearErrors
clearErrors メソッドはフォームのエラーをクリアする。全エラー、単一フィールド、または複数フィールドのエラーを選択的に削除可能。
シグネチャ
clearErrors: (name?: string | string[]) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
name | `string \ | string[] \ | undefined` |
引数パターン
| パターン | 説明 | 例 |
|---|---|---|
引数なし(undefined) | 全エラーを削除 | clearErrors() |
string | 単一フィールドのエラーを削除 | clearErrors("firstName") |
string[] | 複数フィールドのエラーを削除 | clearErrors(["firstName", "lastName"]) |
コード例
全エラーのクリア
import { useForm } from "react-hook-form";
function App() {
const {
register,
clearErrors,
setError,
formState: { errors },
} = useForm();
return (
<form>
<input {...register("firstName", { required: true })} />
{errors.firstName && <span>必須です</span>}
<input {...register("lastName", { required: true })} />
{errors.lastName && <span>必須です</span>}
<button type="button" onClick={() => clearErrors()}>
全エラーをクリア
</button>
</form>
);
}単一フィールドのクリア
clearErrors("firstName");複数フィールドのクリア
clearErrors(["firstName", "lastName"]);ネストフィールドの親指定でクリア
// "test" を指定すると、test.firstName と test.lastName のエラーも削除される
clearErrors("test");
// 特定の子フィールドのみ削除する場合
clearErrors("test.firstName");setError と組み合わせた使用
const onSubmit = async (data: any) => {
// 送信前にサーバーエラーをクリア
clearErrors("root.serverError");
try {
await submitData(data);
} catch {
setError("root.serverError", {
type: "server",
message: "送信に失敗しました",
});
}
};重要なルール / 注意事項
- バリデーションルール自体には影響しない。エラー表示をクリアするだけで、
registerで設定されたルールは維持される。 isValidのformStateプロパティには直接影響しない。有効性はバリデーションルールに基づいて再評価される。- ネストフィールドの親名を指定すると、その配下の全子フィールドのエラーもクリアされる。
setErrorで手動設定したエラーをクリアする場合にも使用する。
useForm — control
control はフォームの内部制御を管理するオブジェクトで、Controller、useWatch、useFormState、useFieldArray などのコンポーネントやフックに渡して使用する。
取得方法
const { control } = useForm();用途
| 渡し先 | 説明 |
|---|---|
Controller | 外部の制御コンポーネント(MUI, Ant Design など)を React Hook Form と統合する |
useWatch | 特定フィールドの値をリアクティブに監視する |
useFormState | フォーム状態を部分的に購読する |
useFieldArray | 動的なフィールド配列を管理する |
useController | Controller のフック版 |
コード例
Controller での使用
import { useForm, Controller } from "react-hook-form";
function App() {
const { control, handleSubmit } = useForm({
defaultValues: { firstName: "" },
});
return (
<form onSubmit={handleSubmit(console.log)}>
<Controller
name="firstName"
control={control}
rules={{ required: "名前は必須です" }}
render={({ field, fieldState: { error } }) => (
<div>
<input {...field} />
{error && <span>{error.message}</span>}
</div>
)}
/>
<input type="submit" />
</form>
);
}useWatch での使用
import { useForm, useWatch } from "react-hook-form";
function WatchedField({ control }: { control: Control }) {
const firstName = useWatch({ control, name: "firstName" });
return <p>現在の値: {firstName}</p>;
}
function App() {
const { control, register } = useForm({
defaultValues: { firstName: "" },
});
return (
<form>
<input {...register("firstName")} />
<WatchedField control={control} />
</form>
);
}useFieldArray での使用
import { useForm, useFieldArray } from "react-hook-form";
function App() {
const { control, register } = useForm({
defaultValues: { items: [{ name: "" }] },
});
const { fields, append, remove } = useFieldArray({
control,
name: "items",
});
return (
<form>
{fields.map((field, index) => (
<input key={field.id} {...register(`items.${index}.name`)} />
))}
<button type="button" onClick={() => append({ name: "" })}>
追加
</button>
</form>
);
}重要なルール / 注意事項
controlオブジェクトの内部プロパティに直接アクセスしてはならない。内部実装用であり、APIが変更される可能性がある。controlはuseFormから取得し、必要なコンポーネントやフックに prop として渡す。useFormContextを使用すると、controlを prop として渡す代わりにコンテキスト経由で取得できる。
useForm — Form
Form コンポーネント(Beta)はフォーム送信を管理するラッパーコンポーネントで、標準の HTML <form> 要素と密接に連携する。デフォルトで POST リクエストを FormData で送信する。
シグネチャ
<Form
control={control}
action="/api/endpoint"
onSubmit={onSubmitHandler}
onSuccess={onSuccessHandler}
onError={onErrorHandler}
headers={headers}
validateStatus={validateStatus}
method="post"
render={renderProp}
>
{children}
</Form>Props
| Name | Type | Default | Description |
|---|---|---|---|
control | Control | — | useForm から取得した control オブジェクト。 |
children | React.ReactNode | — | フォームの子要素。 |
render | ({ submit }) => React.ReactNode | — | ヘッドレスレンダリング用の render prop。React Native で使用。 |
onSubmit | ({ formData, data, event }) => void | — | バリデーション成功後に呼ばれるコールバック。formData、パース済み data、イベントを受け取る。 |
onSuccess | ({ response }) => void | — | サーバーレスポンスが成功した場合のコールバック。 |
onError | ({ response }) => void | — | リクエスト失敗時のコールバック。root.server エラーが自動的に設定される。 |
headers | Record<string, string> | — | リクエストヘッダー。JSON 送信には { 'Content-Type': 'application/json' } を指定。 |
validateStatus | (status: number) => boolean | — | HTTP ステータスコードの成功/失敗判定関数。 |
action | string | — | サーバーエンドポイントの URL。 |
method | string | 'post' | HTTP メソッド。 |
encType | string | — | フォームのエンコーディングタイプ。 |
コード例
React Web — action prop での使用
import { useForm, Form } from "react-hook-form";
function App() {
const { register, control } = useForm({
defaultValues: { name: "", email: "" },
});
return (
<Form
action="/api/submit"
control={control}
onSuccess={() => {
alert("送信成功!");
}}
onError={() => {
alert("送信に失敗しました");
}}
>
<input {...register("name")} />
<input {...register("email")} />
<button type="submit">送信</button>
</Form>
);
}React Web — 手動送信
import { useForm, Form } from "react-hook-form";
function App() {
const { register, control } = useForm();
return (
<Form
onSubmit={async ({ formData, data, event }) => {
await fetch("/api/submit", {
method: "POST",
body: formData,
});
}}
>
<input {...register("name")} />
<button type="submit">送信</button>
</Form>
);
}JSON での送信
<Form
action="/api/submit"
control={control}
headers={{
"Content-Type": "application/json",
}}
onSuccess={() => console.log("成功")}
>
<input {...register("name")} />
<button type="submit">送信</button>
</Form>React Native での使用
import { useForm, Form } from "react-hook-form";
import { View, TextInput, Button } from "react-native";
function App() {
const { register, control } = useForm();
return (
<Form
action="/api/submit"
control={control}
render={({ submit }) => (
<View>
<TextInput {...register("name")} />
<Button title="送信" onPress={() => submit()} />
</View>
)}
/>
);
}バリデーションステータスのカスタマイズ
<Form
action="/api/submit"
control={control}
validateStatus={(status) => status >= 200 && status < 300}
>
...
</Form>重要なルール / 注意事項
- デフォルトでは POST メソッドで FormData として送信する。JSON で送信するには
headersにContent-Type: application/jsonを指定する。 onSubmitコールバックまたはhandleSubmitを使用して、送信前にデータを加工または除外できる。- プログレッシブエンハンスメントは SSR フレームワークでのみ機能し、
useFormのprogressive: trueオプションが必要。 - Beta 機能であるため、API が変更される可能性がある。
- React Native では
renderprop を使用し、submit関数を明示的に呼び出す。 onErrorが呼ばれた場合、root.serverエラーが自動的にformState.errorsに設定される。
useForm — formState
formState はフォーム全体の状態情報を格納するオブジェクトで、ユーザーの操作状況やバリデーション結果を追跡する。パフォーマンス最適化のため Proxy でラップされている。
プロパティ
| Name | Type | Description |
|---|---|---|
isDirty | boolean | いずれかの入力が defaultValues から変更されたかどうか。defaultValues の提供が前提。 |
dirtyFields | object | 変更された個別フィールドを追跡するオブジェクト。defaultValues との比較結果。 |
touchedFields | object | ユーザーが操作した(フォーカス→ブラー)全フィールドを記録するオブジェクト。 |
defaultValues | object | useForm の defaultValues または reset で設定された初期値。 |
isSubmitted | boolean | フォームが送信された後 true になる。reset が呼ばれるまで維持される。 |
isSubmitSuccessful | boolean | ランタイムエラーなしに送信が成功した場合 true。 |
isSubmitting | boolean | フォーム送信中は true。非同期 onSubmit の完了を追跡可能。 |
isLoading | boolean | 非同期 defaultValues の読み込み中に true。非同期デフォルト値のみ対象。 |
submitCount | number | フォーム送信の試行回数。 |
isValid | boolean | バリデーションエラーがない場合 true。mode の設定に依存して初回評価タイミングが異なる。 |
isValidating | boolean | バリデーション実行中に true。 |
validatingFields | object | 非同期バリデーション中のフィールドを特定するオブジェクト。 |
errors | object | フィールドごとのエラーメッセージを格納するオブジェクト。 |
disabled | boolean | useForm の disabled オプションの状態を反映。 |
isReady | boolean | サブスクリプションの初期化が完了したかどうか。 |
Proxy による購読の仕組み
formState は JavaScript の Proxy でラップされており、実際にアクセスされたプロパティのみが購読される。これにより、未使用のプロパティの変更では再レンダリングが発生しない。
正しい使い方
// レンダリング前にプロパティをデストラクチャリングする
const { isDirty, errors } = formState;
// または直接アクセスする
return <p>{formState.errors.name?.message}</p>;誤った使い方
// 条件付きアクセスは購読が登録されない可能性がある
if (someCondition) {
formState.isDirty; // 購読が不安定
}コード例
基本的な使い方
import { useForm } from "react-hook-form";
function App() {
const {
register,
handleSubmit,
formState: {
errors,
isDirty,
isSubmitting,
isValid,
touchedFields,
dirtyFields,
},
} = useForm({
mode: "onChange",
defaultValues: { firstName: "", email: "" },
});
return (
<form onSubmit={handleSubmit(console.log)}>
<input {...register("firstName", { required: true })} />
{errors.firstName && <span>必須フィールドです</span>}
<button type="submit" disabled={!isDirty || !isValid || isSubmitting}>
送信
</button>
</form>
);
}useEffect での使用
// formState 全体を依存配列に含める
const { formState } = useForm();
useEffect(() => {
if (formState.isSubmitSuccessful) {
reset();
}
}, [formState, reset]);重要なルール / 注意事項
- Proxy が機能するには、レンダリング前にプロパティにアクセスまたはデストラクチャリングする必要がある。
useEffectの依存配列にはformState全体を含めること。個別プロパティではなく全体を指定する。- 論理演算子で条件付きにアクセスすると、Proxy の購読が正しく動作しない場合がある。値はデストラクチャリングで取り出すこと。
isDirtyを正確に機能させるには、useFormで全入力のdefaultValuesを提供する必要がある。- ファイル入力はアプリケーションレベルで管理する必要がある。
- カスタムオブジェクトや
Fileインスタンスは dirty 追跡に対応していない。
useForm — getFieldState
getFieldState メソッドは個別フィールドの状態(dirty, touched, エラー)を取得する。v7.25.0 以降で利用可能。
シグネチャ
getFieldState: (
name: string,
formState?: FormState
) => {
isDirty: boolean;
isTouched: boolean;
invalid: boolean;
error: FieldError | undefined;
}引数
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | 状態を取得するフィールド名。 |
formState | FormState | No | formState オブジェクト。フォーム状態の購読が別途行われていない場合に必要。 |
戻り値
| Name | Type | Description |
|---|---|---|
isDirty | boolean | フィールドが defaultValues から変更されたかどうか。dirtyFields の購読が前提。 |
isTouched | boolean | フィールドがフォーカス→ブラーされたかどうか。touchedFields の購読が前提。 |
invalid | boolean | フィールドが有効でないかどうか。errors の購読が前提。 |
error | `FieldError \ | undefined` |
コード例
useForm と組み合わせた使用
import { useForm } from "react-hook-form";
function App() {
const {
register,
getFieldState,
formState,
formState: { isDirty, errors },
} = useForm({
mode: "onChange",
defaultValues: { firstName: "" },
});
// formState を購読済みなので第2引数は不要
const fieldState = getFieldState("firstName");
return (
<form>
<input {...register("firstName", { required: true })} />
<p>isDirty: {fieldState.isDirty ? "はい" : "いいえ"}</p>
<p>isTouched: {fieldState.isTouched ? "はい" : "いいえ"}</p>
<p>invalid: {fieldState.invalid ? "はい" : "いいえ"}</p>
{fieldState.error && <p>エラー: {fieldState.error.message}</p>}
</form>
);
}formState を明示的に渡す
const { getFieldState, formState } = useForm();
// formState を第2引数に渡す
const fieldState = getFieldState("firstName", formState);useFormContext と組み合わせた使用
import { useFormContext } from "react-hook-form";
function FieldInfo({ name }: { name: string }) {
const { getFieldState, formState } = useFormContext();
const { isDirty, error } = getFieldState(name, formState);
return (
<div>
{isDirty && <span>変更あり</span>}
{error && <span>{error.message}</span>}
</div>
);
}useFormState と組み合わせた使用
import { useForm, useFormState } from "react-hook-form";
function App() {
const { register, control, getFieldState } = useForm();
const formState = useFormState({ control });
const { isDirty, isTouched } = getFieldState("firstName", formState);
}重要なルール / 注意事項
- v7.25.0 以降で利用可能。
- フィールド名が登録済みのフィールドに一致しない場合、
isDirty: false、isTouched: false、invalid: false、error: undefinedが返される。 formStateの購読が前提条件。以下のいずれかの方法で購読が必要:useForm()からformStateをデストラクチャリングuseFormContext()でformStateを取得useFormState()でformStateを取得- 第2引数に
formStateを直接渡す - 購読されていない
formStateプロパティに対応する戻り値は正確でない場合がある。
useForm — getValues
getValues メソッドはフォームの値を取得する。watch と異なり、再レンダリングをトリガーせず、入力変更の購読も行わない。
シグネチャ
getValues: (payload?: string | string[]) => Object引数
| Name | Type | Required | Description |
|---|---|---|---|
payload | `string \ | string[] \ | undefined` |
引数パターン
| パターン | 戻り値 | 説明 |
|---|---|---|
| 引数なし | Record<string, unknown> | 全フォーム値をオブジェクトで返す |
string | unknown | 指定フィールドの値を返す |
string[] | unknown[] | 指定フィールドの値を配列で返す |
コード例
全フォーム値の取得
import { useForm } from "react-hook-form";
function App() {
const { register, getValues } = useForm({
defaultValues: { firstName: "太郎", lastName: "山田" },
});
const handleClick = () => {
const values = getValues();
console.log(values);
// { firstName: "太郎", lastName: "山田" }
};
return (
<form>
<input {...register("firstName")} />
<input {...register("lastName")} />
<button type="button" onClick={handleClick}>
値を取得
</button>
</form>
);
}単一フィールドの取得
const firstName = getValues("firstName");
// "太郎"複数フィールドの取得
const [firstName, lastName] = getValues(["firstName", "lastName"]);
// ["太郎", "山田"]ネストフィールドの取得
const email = getValues("user.email");
const firstItem = getValues("items.0.title");dirty フィールドのみ取得
const dirtyValues = getValues(undefined, { dirtyFields: true });touched フィールドのみ取得
const touchedValues = getValues(undefined, { touchedFields: true });条件分岐での使用
const onSubmit = () => {
const type = getValues("type");
if (type === "premium") {
// プレミアム向け処理
}
};重要なルール / 注意事項
- 再レンダリングをトリガーしない。また、入力変更を購読しない。値の変更に応じて UI を更新する場合は
watchまたはuseWatchを使用すること。 - 初回レンダリング前(
registerの前)はuseFormのdefaultValuesを返す。 - イベントハンドラやコールバック内で現在のフォーム値を取得する場合に最適。
- リアクティブな値の監視には適さない。
useForm — handleSubmit
handleSubmit メソッドはフォーム送信を処理する。バリデーションを実行し、成功時とエラー時のコールバックを呼び分ける。
シグネチャ
handleSubmit: (
onValid: SubmitHandler<TFieldValues>,
onInvalid?: SubmitErrorHandler<TFieldValues>
) => (e?: React.BaseSyntheticEvent) => Promise<void>型定義
type SubmitHandler<TFieldValues> = (
data: TFieldValues,
event?: React.BaseSyntheticEvent
) => void | Promise<void>;
type SubmitErrorHandler<TFieldValues> = (
errors: FieldErrors<TFieldValues>,
event?: React.BaseSyntheticEvent
) => void | Promise<void>;引数
| Name | Type | Required | Description |
|---|---|---|---|
onValid | SubmitHandler | Yes | バリデーション成功時に呼ばれるコールバック。バリデーション済みのフォームデータを受け取る。 |
onInvalid | SubmitErrorHandler | No | バリデーション失敗時に呼ばれるコールバック。エラーオブジェクトを受け取る。 |
コード例
基本的な使い方
import { useForm } from "react-hook-form";
function App() {
const { register, handleSubmit } = useForm();
const onSubmit = (data: any, e?: React.BaseSyntheticEvent) => {
console.log("送信データ:", data);
};
const onError = (errors: any, e?: React.BaseSyntheticEvent) => {
console.log("バリデーションエラー:", errors);
};
return (
<form onSubmit={handleSubmit(onSubmit, onError)}>
<input {...register("firstName", { required: true })} />
<input type="submit" />
</form>
);
}非同期送信と try-catch
const onSubmit = async (data: FormValues) => {
try {
const response = await fetch("/api/submit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!response.ok) throw new Error("送信失敗");
} catch (error) {
// エラーハンドリングを実装すること
console.error(error);
}
};
return <form onSubmit={handleSubmit(onSubmit)}>...</form>;ボタンクリックでの呼び出し
<button onClick={handleSubmit(onSubmit)}>送信</button>重要なルール / 注意事項
handleSubmitは非同期コールバックをサポートする。async/awaitが使用可能。handleSubmitは内部で発生したエラーを飲み込まない。onSubmitコールバック内で非同期リクエストを行う場合は、必ずtry-catchでエラーハンドリングすること。disabledな input のフォームデータ値はundefinedになる。値を保持したい場合はdisabledではなくreadOnlyを使用するか、<fieldset disabled>で囲む。handleSubmitの戻り値はPromise<void>であるため、event.preventDefault()は自動的に呼ばれる。
useForm — register
register メソッドは input 要素をフォームに登録し、バリデーションルールを適用する。戻り値を input 要素にスプレッドすることで、値の追跡と検証が可能になる。
シグネチャ
register: (name: string, options?: RegisterOptions) => {
ref: React.Ref;
name: string;
onChange: ChangeHandler;
onBlur: ChangeHandler;
}引数
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | フィールドの一意な名前。ドット記法でネストをサポート。 |
options | RegisterOptions | No | バリデーションルールと動作設定。 |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
required | `boolean \ | string \ | { value: boolean, message: string }` |
minLength | `number \ | { value: number, message: string }` | — |
maxLength | `number \ | { value: number, message: string }` | — |
min | `number \ | string \ | { value: number \ |
max | `number \ | string \ | { value: number \ |
pattern | `RegExp \ | { value: RegExp, message: string }` | — |
validate | `Function \ | Record<string, Function>` | — |
valueAsNumber | boolean | false | 値を Number に変換してからバリデーションする。setValueAs と併用不可。 |
valueAsDate | boolean | false | 値を Date に変換してからバリデーションする。setValueAs と併用不可。 |
setValueAs | (value: any) => any | — | カスタム変換関数。valueAsNumber / valueAsDate と併用不可。 |
disabled | boolean | false | 入力を無効にする。無効な入力の値は undefined になる。 |
onChange | (e: SyntheticEvent) => void | — | カスタムの change イベントハンドラ。RHF の内部ハンドラと共に実行される。 |
onBlur | (e: SyntheticEvent) => void | — | カスタムの blur イベントハンドラ。RHF の内部ハンドラと共に実行される。 |
value | unknown | — | 静的な値の割り当て。useEffect 内で使用する。 |
shouldUnregister | boolean | false | true の場合、アンマウント時にフィールドを登録解除する。 |
deps | `string \ | string[]` | — |
戻り値
| Name | Type | Description |
|---|---|---|
ref | React.Ref | フックと DOM 要素を接続する React ref。 |
name | string | 登録されたフィールド名。 |
onChange | ChangeHandler | input の change イベントを処理するハンドラ。 |
onBlur | ChangeHandler | input の blur イベントを処理するハンドラ。 |
ネストフィールド記法
| 記法 | 送信結果 |
|---|---|
register("firstName") | { firstName: 'value' } |
register("user.email") | { user: { email: 'value' } } |
register("items.0.title") | { items: [{ title: 'value' }] } |
コード例
基本的な使い方
import { useForm } from "react-hook-form";
function App() {
const { register, handleSubmit, formState: { errors } } = useForm({
defaultValues: { firstName: "", email: "" },
});
return (
<form onSubmit={handleSubmit(console.log)}>
<input {...register("firstName", { required: "名前は必須です" })} />
{errors.firstName && <p>{errors.firstName.message}</p>}
<input
{...register("email", {
required: "メールは必須です",
pattern: {
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: "有効なメールアドレスを入力してください",
},
})}
/>
{errors.email && <p>{errors.email.message}</p>}
<input type="submit" />
</form>
);
}カスタムバリデーション
<input
{...register("username", {
validate: {
checkLength: (value) =>
value.length >= 3 || "ユーザー名は3文字以上必要です",
checkFormat: (value) =>
/^[a-zA-Z0-9]+$/.test(value) || "英数字のみ使用可能です",
},
})}
/>非同期バリデーション
<input
{...register("email", {
validate: async (value) => {
const response = await fetch(`/api/check-email?email=${value}`);
const { available } = await response.json();
return available || "このメールアドレスは既に使用されています";
},
})}
/>値の変換
<input
type="number"
{...register("age", { valueAsNumber: true, min: 18 })}
/>
<input
{...register("price", {
setValueAs: (v) => parseInt(v, 10),
})}
/>依存フィールド
<input {...register("password")} type="password" />
<input
{...register("confirmPassword", {
deps: ["password"],
validate: (value, formValues) =>
value === formValues.password || "パスワードが一致しません",
})}
type="password"
/>重要なルール / 注意事項
- フィールド名は一意でなければならず、数字で始めることはできない。
- ネストフィールドにはドット記法を使用する(ブラケット記法ではなく)。
disabledな入力のフォームデータ値はundefinedになる。- 個別のオプションを削除することはできない。
falseに更新する必要がある。 - 予約語
ref、_fをフィールド名として使用しないこと。 valueAsNumber、valueAsDate、setValueAsは互いに排他的。
useForm — reset
reset メソッドはフォーム全体の状態(値、エラー、dirty 状態など)をリセットする。オプションで特定の状態のみ保持しつつリセットすることも可能。
シグネチャ
reset: <T extends FieldValues>(
values?: T | ResetAction<T>,
options?: KeepStateOptions
) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
values | `T \ | ResetAction<T>` | No |
options | KeepStateOptions | No | 状態保持オプション。 |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
keepErrors | boolean | false | エラーを保持する。ただし後続のユーザー操作で更新される可能性がある。 |
keepDirty | boolean | false | isDirty と dirtyFields の状態を保持する。実際の入力値は反映しない。 |
keepDirtyValues | boolean | false | dirty なフィールドの値を保持し、クリーンなフィールドのみ更新する。 |
keepValues | boolean | false | フォーム入力値を変更しない。 |
keepDefaultValues | boolean | false | 元の defaultValues を保持する。 |
keepIsSubmitted | boolean | false | isSubmitted の状態を保持する。 |
keepTouched | boolean | false | touchedFields の状態を保持する。 |
keepIsValid | boolean | false | isValid の状態を一時的に保持する。 |
keepSubmitCount | boolean | false | submitCount を保持する。 |
keepFieldsRef | boolean | false | フィールド参照のリセットをスキップし、再登録を避ける。マスク入力ライブラリとの連携に有用(v7.60+)。 |
コード例
基本的なリセット
const { register, handleSubmit, reset } = useForm({
defaultValues: { firstName: "", lastName: "" },
});
// デフォルト値にリセット
reset();
// 新しい値でリセット(defaultValues も更新)
reset({ firstName: "太郎", lastName: "山田" });特定の状態を保持してリセット
// dirty なフィールドの値を保持
reset(undefined, { keepDirtyValues: true });
// エラーを保持してリセット
reset(undefined, { keepErrors: true });
// 値を保持して状態のみリセット
reset(undefined, { keepValues: true });送信成功後のリセット
const { handleSubmit, reset, formState } = useForm();
useEffect(() => {
if (formState.isSubmitSuccessful) {
reset();
}
}, [formState.isSubmitSuccessful, reset]);関数でリセット値を計算
reset((formValues) => ({
...formValues,
firstName: "リセット済み",
}));外部データでリセット
useEffect(() => {
async function fetchData() {
const response = await fetch("/api/user");
const data = await response.json();
reset(data);
}
fetchData();
}, [reset]);重要なルール / 注意事項
- Controller コンポーネントをリセットするには、
useFormにdefaultValuesを提供する必要がある。 useFormのuseEffectが実行される前にresetを呼び出してはならない。サブスクリプションの初期化が必要。- 送信成功後のリセットは
useEffect内で行い、実行順序を保証すること。 resetに値を渡すと、defaultValuesも更新される(keepDefaultValues: trueを指定しない限り)。valuesを渡さずoptionsのみ渡す場合は、第1引数にundefinedを指定する。
useForm — resetDefaultValues
resetDefaultValues メソッドはフォームのデフォルト値を更新し、それに伴い dirty/valid 状態を再計算する。v7.77.0 以降で利用可能。reset() と異なり、ユーザーが入力した値には影響せず、デフォルト値の基準線のみを更新する。
バージョン要件
- v7.77.0+
シグネチャ
resetDefaultValues: (
values: DefaultValues<TFieldValues> | TFieldValues,
options?: {
keepDirty?: boolean;
keepIsValid?: boolean;
}
) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
values | `DefaultValues<TFieldValues> \ | TFieldValues` | Yes |
options | Object | No | 状態保持オプション。 |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
keepDirty | boolean | false | true にすると、現在の dirtyFields 状態を保持する。デフォルト値更新後の dirty 状態再計算をスキップする。 |
keepIsValid | boolean | false | true にすると、現在の isValid 状態を保持する。 |
reset() との違い
resetDefaultValues | reset | |
|---|---|---|
| ユーザー入力値への影響 | なし(値はそのまま) | あり(デフォルト値に戻す) |
| デフォルト値の更新 | あり | あり(値を渡した場合) |
| dirty 状態の再計算 | あり(新しいデフォルト値基準) | あり |
| isSubmitted のリセット | なし | あり |
コード例
サーバーデータでデフォルト値を更新
import { useForm } from "react-hook-form";
type FormValues = {
firstName: string;
lastName: string;
email: string;
};
function UserProfileForm({ userId }: { userId: string }) {
const { register, handleSubmit, resetDefaultValues } = useForm<FormValues>({
defaultValues: { firstName: "", lastName: "", email: "" },
});
// 保存成功後にデフォルト値を現在の値に更新(dirty 状態をクリア)
const onSubmit = async (data: FormValues) => {
await saveUser(userId, data);
// ユーザーが入力した値はそのままに、デフォルト値を更新
resetDefaultValues(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<input {...register("email")} />
<button type="submit">保存</button>
</form>
);
}keepDirty オプションで状態を保持
// デフォルト値は更新するが、dirty 状態は現在のまま保持
resetDefaultValues(newDefaults, { keepDirty: true });subscribe との組み合わせ
const { subscribe, resetDefaultValues } = useForm({
defaultValues: { name: "" },
});
// サブスクリプション内で resetDefaultValues は呼ばないこと(無限ループの原因)重要なルール / 注意事項
resetDefaultValuesはユーザーの入力済み値を変更しない。デフォルト値の基準線のみを更新する。- 呼び出し後、
isDirtyは新しいデフォルト値と現在の入力値の差分で再計算される。 subscribeのコールバック内で呼び出すと無限ループになるため禁止。- v7.77.0 以前は
reset(values)でデフォルト値と入力値を同時に更新する必要があったが、resetDefaultValuesにより分離が可能になった。
Related
- reset
- resetField
- formState
- useForm
useForm — resetField
resetField メソッドは個別のフィールドの状態と値をリセットする。フォーム全体ではなく、特定のフィールドのみをリセットしたい場合に使用する。
シグネチャ
resetField: (name: string, options?: ResetFieldOptions) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | リセットするフィールド名。register で登録済みのフィールド名と完全に一致する必要がある。 |
options | ResetFieldOptions | No | リセット動作のカスタマイズ。 |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
keepError | boolean | false | true の場合、フィールドのバリデーションエラーを保持する。 |
keepDirty | boolean | false | true の場合、dirtyFields の状態を保持する。 |
keepTouched | boolean | false | true の場合、touchedFields の状態を保持する。 |
defaultValue | unknown | — | リセット先のカスタム値。指定するとフィールドの値と defaultValue の両方が更新される。undefined は不可。省略すると元の defaultValue に戻る。 |
コード例
基本的なリセット
import { useForm } from "react-hook-form";
function App() {
const { register, resetField, formState: { errors } } = useForm({
defaultValues: { firstName: "", lastName: "" },
});
return (
<form>
<input {...register("firstName", { required: true })} />
{errors.firstName && <span>必須です</span>}
<button type="button" onClick={() => resetField("firstName")}>
firstName をリセット
</button>
</form>
);
}エラーを保持してリセット
resetField("firstName", { keepError: true });新しいデフォルト値でリセット
resetField("firstName", { defaultValue: "新しい名前" });dirty 状態を保持してリセット
resetField("firstName", { keepDirty: true });副作用
resetField を呼び出すと、以下のフォーム状態が自動的に再評価される:
isValid— バリデーションが再実行され、フォームの有効性が再計算される。isDirty— フィールドのリセットにより、フォーム全体の dirty 状態が再計算される。
重要なルール / 注意事項
- フィールド名は
registerで登録されたものと完全一致する必要がある。一致しない場合、操作は暗黙的に失敗する。 defaultValueオプションにundefinedは渡せない。defaultValueを指定すると、そのフィールドのdefaultValue自体が更新される(以降のisDirty比較に影響)。- フォーム全体をリセットする場合は
resetメソッドを使用すること。
useForm — setError
setError メソッドはフィールドに手動でエラーを設定する。サーバーサイドバリデーションの結果をフォームに反映する場合や、API エラーを表示する場合に使用する。
シグネチャ
setError: (
name: string,
error: { type: string; message?: string; types?: Record<string, string> },
config?: { shouldFocus?: boolean }
) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | エラーを設定するフィールド名。root.serverError のようなルートエラーもサポート。 |
error | FieldError | Yes | エラーオブジェクト。 |
config | { shouldFocus?: boolean } | No | フォーカス制御。 |
error オブジェクト
| Name | Type | Required | Description |
|---|---|---|---|
type | string | Yes | エラーの種類を示す識別子(例: "required", "server", "custom")。 |
message | string | No | 表示用のエラーメッセージ。 |
types | Record<string, string> | No | 複数のエラーを設定する場合に使用。criteriaMode: "all" との併用が必要。 |
config オプション
| Name | Type | Default | Description |
|---|---|---|---|
shouldFocus | boolean | false | true の場合、エラー設定時にフィールドへフォーカスする。登録済み input にのみ有効。disabled な input では無視される。 |
コード例
基本的な使い方
import { useForm } from "react-hook-form";
function App() {
const {
register,
handleSubmit,
setError,
formState: { errors },
} = useForm();
const onSubmit = async (data: any) => {
const response = await fetch("/api/submit", {
method: "POST",
body: JSON.stringify(data),
});
if (!response.ok) {
const result = await response.json();
// サーバーから返されたフィールドエラーを設定
if (result.errors?.email) {
setError("email", {
type: "server",
message: result.errors.email,
});
}
}
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("email")} />
{errors.email && <span>{errors.email.message}</span>}
<input type="submit" />
</form>
);
}ルートエラー(サーバーエラー)
const onSubmit = async (data: any) => {
try {
await fetch("/api/submit", { method: "POST", body: JSON.stringify(data) });
} catch {
setError("root.serverError", {
type: "400",
message: "サーバーエラーが発生しました",
});
}
};
// エラー表示
{errors.root?.serverError && (
<p>{errors.root.serverError.message}</p>
)}複数エラー
setError("username", {
types: {
minLength: "3文字以上必要です",
pattern: "英数字のみ使用可能です",
},
});フォーカス付きエラー設定
setError("email", {
type: "manual",
message: "このメールは既に登録されています",
}, { shouldFocus: true });重要なルール / 注意事項
registerで設定されたバリデーションルールが通過する場合、setErrorで設定したエラーは永続化されない。例えば、minLength: 4が満たされているフィールドに手動でエラーを設定しても、送信はブロックされない。- 未登録フィールドに設定したエラーは、
clearErrorsで明示的にクリアするまで残る。 setErrorはisValidを強制的にfalseにする。ただし最終的な有効性はスキーマやregisterのバリデーションルールに基づく。rootエラーはフォーム送信をまたいで永続化されない。- フィールド名に
typeやtypesを使用しないこと。エラーオブジェクトと競合する。 handleSubmitのコールバック内で使用するのが一般的なパターン。
useForm — setFocus
setFocus メソッドは登録済みの input フィールドにプログラム的にフォーカスを設定する。初期フォーカスや特定操作後のフォーカス移動に使用する。
シグネチャ
setFocus: (name: string, options?: { shouldSelect?: boolean }) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | フォーカスを設定するフィールド名。 |
options | { shouldSelect?: boolean } | No | フォーカスオプション。 |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
shouldSelect | boolean | false | true にすると、フォーカス時に入力内容を全選択する。 |
コード例
初期フォーカス
import { useEffect } from "react";
import { useForm } from "react-hook-form";
type FormValues = {
firstName: string;
lastName: string;
};
function App() {
const { register, handleSubmit, setFocus } = useForm<FormValues>();
useEffect(() => {
setFocus("firstName");
}, [setFocus]);
return (
<form onSubmit={handleSubmit(console.log)}>
<input {...register("firstName")} placeholder="名" />
<input {...register("lastName")} placeholder="姓" />
<input type="submit" />
</form>
);
}内容を選択してフォーカス
setFocus("firstName", { shouldSelect: true });エラー時のフォーカス移動
const onError = (errors: FieldErrors) => {
const firstErrorField = Object.keys(errors)[0];
if (firstErrorField) {
setFocus(firstErrorField as keyof FormValues);
}
};
return <form onSubmit={handleSubmit(onSubmit, onError)}>...</form>;ボタンクリックでフォーカス
<button type="button" onClick={() => setFocus("email")}>
メール入力にフォーカス
</button>重要なルール / 注意事項
setFocusはregisterのrefを使用してfocus()メソッドを呼び出す。フィールドがregisterで登録され、refが正しく DOM に接続されている必要がある。resetの直後にsetFocusを呼び出してはならない。resetは全入力の参照を削除するため、フォーカスが機能しない。- カスタムコンポーネントを使用する場合は、
refが内部の input 要素に正しく転送されている必要がある。 shouldFocusErrorオプション(useFormのオプション)を使用すると、バリデーション失敗時に自動的に最初のエラーフィールドにフォーカスされる。手動でのフォーカス制御が不要な場合はそちらを活用すること。
useForm — setValue
setValue メソッドは登録済みフィールドの値をプログラム的に設定する。バリデーションや dirty 状態の更新もオプションで制御可能。
シグネチャ
setValue: (
name: string,
value: unknown,
config?: {
shouldValidate?: boolean;
shouldDirty?: boolean;
shouldTouch?: boolean;
}
) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | 対象フィールド名。ドット記法でネストフィールドを指定。 |
value | unknown | Yes | 設定する値。undefined は不可。 |
config | SetValueConfig | No | 状態更新オプション。 |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
shouldValidate | boolean | false | true にすると、値の設定後にバリデーションを実行する。errors と isValid が更新される。フィールドレベルでのみ touchedFields が更新される。 |
shouldDirty | boolean | false | true にすると、defaultValues と比較して dirtyFields と isDirty を更新する。フィールドレベルでのみ更新。 |
shouldTouch | boolean | false | true にすると、フィールドを touched 状態にする。 |
コード例
基本的な使い方
import { useForm } from "react-hook-form";
function App() {
const { register, setValue, handleSubmit } = useForm({
defaultValues: { firstName: "", lastName: "" },
});
return (
<form onSubmit={handleSubmit(console.log)}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<button type="button" onClick={() => setValue("firstName", "太郎")}>
名前を設定
</button>
<input type="submit" />
</form>
);
}バリデーション付き
setValue("firstName", "太郎", { shouldValidate: true });dirty 状態の更新付き
setValue("firstName", "太郎", { shouldDirty: true });複数オプション
setValue("firstName", "太郎", {
shouldValidate: true,
shouldDirty: true,
shouldTouch: true,
});ドット記法によるネストフィールド
// 推奨: ドット記法で個別指定
setValue("user.firstName", "太郎");
setValue("user.lastName", "山田");
// 非推奨: オブジェクトをまとめて渡す(パフォーマンスが低下する可能性)
setValue("user", { firstName: "太郎", lastName: "山田" });依存フィールドの自動計算
const { watch, setValue, formState } = useForm();
const [a, b] = watch(["a", "b"]);
useEffect(() => {
if (formState.touchedFields.a && formState.touchedFields.b) {
setValue("c", `${a} ${b}`);
}
}, [setValue, a, b, formState]);重要なルール / 注意事項
- ドット記法でフィールドを個別に指定するのがパフォーマンス面で推奨される。ネストオブジェクトをまとめて渡すより効率的。
- フィールド配列を更新する場合は、
setValueよりもuseFieldArrayのreplaceやupdateメソッドを使用することを推奨。 - 再レンダリングはエラーの修正/発生時、または
dirty/touched状態が変化した場合にのみ発生する。 - 未登録フィールドに
setValueを使用しても新しいフィールドは作成されない。 setValueを使用する前にフィールドをregisterで登録すること。valueにundefinedを渡すことはできない。
useForm — setValues
setValues メソッドは複数のフォームフィールドの値を一括で更新する。v7.74.0 以降で利用可能。個別フィールドを順番に setValue で更新するよりも効率的で、冗長な深いクローンをスキップしてパフォーマンスを向上させる。
バージョン要件
- v7.74.0+
シグネチャ
setValues: (
value: Partial<TFieldValues> | ((current: TFieldValues) => Partial<TFieldValues>),
options?: {
shouldValidate?: boolean;
shouldDirty?: boolean;
shouldTouch?: boolean;
}
) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
value | `Partial<TFieldValues> \ | ResetAction<TFieldValues>` | Yes |
options | SetValueConfig | No | 状態更新オプション。 |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
shouldValidate | boolean | false | true にすると、値の設定後にバリデーションを実行する。 |
shouldDirty | boolean | false | true にすると、dirtyFields と isDirty を更新する。 |
shouldTouch | boolean | false | true にすると、対象フィールドを touched 状態にする。 |
コード例
オブジェクトで一括設定
import { useForm } from "react-hook-form";
type FormValues = {
firstName: string;
lastName: string;
email: string;
};
function App() {
const { register, setValues } = useForm<FormValues>({
defaultValues: { firstName: "", lastName: "", email: "" },
});
const fillForm = () => {
setValues({
firstName: "太郎",
lastName: "山田",
email: "taro@example.com",
});
};
return (
<form>
<input {...register("firstName")} />
<input {...register("lastName")} />
<input {...register("email")} />
<button type="button" onClick={fillForm}>
フォームを埋める
</button>
</form>
);
}コールバック関数で更新
// 現在の値を元に一部のフィールドを更新
setValues((currentValues) => ({
...currentValues,
firstName: "更新後の名前",
}));バリデーション付きで設定
setValues(
{ firstName: "太郎", email: "taro@example.com" },
{ shouldValidate: true, shouldDirty: true }
);重要なルール / 注意事項
setValueの一括版として設計されており、複数フィールドを効率的に更新する。各フィールドで個別のsetValueを呼ぶよりパフォーマンスが高い。undefinedの値を含むフィールドは更新されない。- フィールド配列の操作には
useFieldArrayのreplaceやupdateメソッドを使用すること。
Related
- setValue
- reset
- useForm
useForm — subscribe
subscribe メソッドは、コンポーネントの再レンダリングなしにフォーム状態の変更を購読する。外部システムとの連携やアナリティクスなど、UI 更新が不要な場面に適している。
シグネチャ
subscribe: (props: {
name?: string[];
formState?: Partial<ReadFormState>;
callback: (state: FormState) => void;
exact?: boolean;
}) => () => voidProps
| Name | Type | Default | Description |
|---|---|---|---|
name | `string[] \ | undefined` | undefined |
formState | Partial<ReadFormState> | — | 購読する状態プロパティを選択。values, isDirty, dirtyFields, touchedFields, isValid, errors, validatingFields, isValidating が指定可能。 |
callback | (state: FormState) => void | — | 状態変更時に呼ばれるコールバック関数。指定した状態がデストラクチャリングで取得可能。 |
exact | boolean | false | フィールド名の完全一致を有効にする。 |
戻り値
| Type | Description |
|---|---|
() => void | 購読解除関数。呼び出すと購読を停止する。 |
コード例
基本的な値の購読
import { useEffect } from "react";
import { useForm } from "react-hook-form";
function App() {
const { register, subscribe } = useForm({
defaultValues: { name: "", email: "" },
});
useEffect(() => {
const unsubscribe = subscribe({
formState: { values: true },
callback: ({ values }) => {
console.log("フォーム値が変更されました:", values);
},
});
return () => unsubscribe();
}, [subscribe]);
return (
<form>
<input {...register("name")} />
<input {...register("email")} />
</form>
);
}特定フィールドの購読
useEffect(() => {
const unsubscribe = subscribe({
name: ["email"],
formState: { values: true, errors: true },
callback: ({ values, errors }) => {
console.log("email:", values.email);
if (errors.email) {
console.log("エラー:", errors.email.message);
}
},
});
return () => unsubscribe();
}, [subscribe]);バリデーション状態の購読
useEffect(() => {
const unsubscribe = subscribe({
formState: { isValid: true, isDirty: true },
callback: ({ isValid, isDirty }) => {
// 外部システムにフォーム状態を同期
analytics.track("formState", { isValid, isDirty });
},
});
return () => unsubscribe();
}, [subscribe]);重要なルール / 注意事項
- コールバック内で
setValueやresetなどの状態変更メソッドを呼び出してはならない。無限ループの原因になる。 - 再レンダリングは発生しない。UI の更新が必要な場合は
watchやuseWatchを使用すること。 - メモリリーク防止のため、必ずクリーンアップ関数で
unsubscribeを実行すること。 watchのコールバック形式の代替として推奨される方法。
useForm — trigger
trigger メソッドはバリデーションを手動で実行する。フォーム全体、単一フィールド、または複数フィールドのバリデーションをプログラム的にトリガーできる。
シグネチャ
trigger: (
name?: string | string[],
options?: { shouldFocus?: boolean }
) => Promise<boolean>引数
| Name | Type | Required | Description |
|---|---|---|---|
name | `string \ | string[] \ | undefined` |
options | { shouldFocus?: boolean } | No | フォーカスオプション。 |
引数パターン
| パターン | 説明 | 例 |
|---|---|---|
引数なし(undefined) | 全フィールドのバリデーションを実行 | trigger() |
string | 単一フィールドのバリデーションを実行 | trigger("email") |
string[] | 複数フィールドのバリデーションを実行 | trigger(["email", "name"]) |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
shouldFocus | boolean | false | true にすると、エラー発生時に対象フィールドにフォーカスする。登録済み input にのみ有効。 |
戻り値
| Type | Description |
|---|---|
Promise<boolean> | バリデーション成功時は true、失敗時は false。 |
コード例
全フィールドのバリデーション
import { useForm } from "react-hook-form";
function App() {
const { register, trigger, formState: { errors } } = useForm();
const validateAll = async () => {
const isValid = await trigger();
console.log("フォームは有効:", isValid);
};
return (
<form>
<input {...register("firstName", { required: true })} />
<input {...register("email", { required: true })} />
<button type="button" onClick={validateAll}>
全バリデーション
</button>
</form>
);
}単一フィールドのバリデーション
const validateEmail = async () => {
const isValid = await trigger("email");
if (isValid) {
console.log("メールアドレスは有効です");
}
};複数フィールドのバリデーション
const validateStep = async () => {
const isValid = await trigger(["firstName", "lastName", "email"]);
if (isValid) {
// 次のステップに進む
goToNextStep();
}
};ネストフィールドのバリデーション
await trigger("user.email");
await trigger("items.0.title");フォーカス付きバリデーション
await trigger("email", { shouldFocus: true });ウィザード形式フォームでの使用
function WizardForm() {
const { register, trigger } = useForm();
const [step, setStep] = useState(1);
const nextStep = async () => {
const fieldsToValidate =
step === 1
? ["firstName", "lastName"]
: ["email", "phone"];
const isValid = await trigger(fieldsToValidate);
if (isValid) {
setStep((prev) => prev + 1);
}
};
return (
<form>
{step === 1 && (
<>
<input {...register("firstName", { required: true })} />
<input {...register("lastName", { required: true })} />
</>
)}
{step === 2 && (
<>
<input {...register("email", { required: true })} />
<input {...register("phone")} />
</>
)}
<button type="button" onClick={nextStep}>
次へ
</button>
</form>
);
}重要なルール / 注意事項
- 単一フィールド名(
string)を指定した場合のみ、レンダリングの最適化が適用される。そのフィールドのみが再レンダリングされる。 string[]またはundefinedを指定した場合は、formState全体の再レンダリングがトリガーされる。- 非同期バリデーションにも対応。
Promise<boolean>が返されるため、awaitで結果を待機できる。 shouldFocusオプションはregisterでrefが登録されている input にのみ機能する。
useForm — unregister
unregister メソッドは、登録済みの input フィールドの登録を解除し、対応するバリデーションルールと値を削除する。単一または複数のフィールドを一度に解除可能。
シグネチャ
unregister: (name: string | string[], options?: UnregisterOptions) => void引数
| Name | Type | Required | Description |
|---|---|---|---|
name | `string \ | string[]` | Yes |
options | UnregisterOptions | No | 状態保持オプション。 |
オプション
| Name | Type | Default | Description |
|---|---|---|---|
keepDirty | boolean | false | isDirty と dirtyFields の状態を保持する。ただし後続の入力操作が defaultValues との比較で状態を更新する可能性がある。 |
keepTouched | boolean | false | touchedFields から入力を削除しない。 |
keepIsValid | boolean | false | isValid の状態を保持する。ただしスキーマバリデーションの場合は更新される可能性がある。 |
keepError | boolean | false | エラー状態のクリアを防止する。 |
keepValue | boolean | false | 入力の現在の値を保持する。 |
keepDefaultValue | boolean | false | useForm で定義された defaultValue を保持する。 |
コード例
基本的な使い方
import { useForm } from "react-hook-form";
function App() {
const { register, unregister, handleSubmit } = useForm<{
firstName: string;
lastName: string;
}>();
return (
<form onSubmit={handleSubmit(console.log)}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<button type="button" onClick={() => unregister("lastName")}>
lastName を解除
</button>
<input type="submit" />
</form>
);
}複数フィールドの解除
unregister(["firstName", "lastName"]);オプション付き
unregister("lastName", {
keepDirty: true,
keepError: true,
});重要なルール / 注意事項
- 組み込みバリデーションは削除される。
registerで設定したバリデーションルールは、登録解除と同時に無効になる。 - スキーマバリデーション(Yup, Zod など)は影響を受けない。スキーマ定義は登録解除後も残るため、スキーマ側も適宜調整する必要がある。
- 登録解除後は対応する input コンポーネントをアンマウントすること。アンマウントしない場合、
registerのコールバックが再度フィールドを登録してしまう。 - 動的フォームで条件付きフィールドを削除する場合に特に有用。
useForm — watch
watch メソッドは指定したフィールドの値の変更を監視し、条件付きレンダリングや値の表示に使用する。値が変更されると再レンダリングがトリガーされる。
シグネチャ(オーバーロード)
単一フィールド監視
watch(name: string, defaultValue?: unknown): unknown複数フィールド監視
watch(names: string[], defaultValue?: Record<string, unknown>): unknown[]全フィールド監視
watch(): Record<string, unknown>コールバック監視(非推奨)
watch(
callback: (data: Record<string, unknown>, info: { name?: string; type?: string }) => void,
defaultValues?: Record<string, unknown>
): { unsubscribe: () => void }コールバック形式は非推奨。代わりに subscribe() メソッドを使用すること。引数
| Name | Type | Description |
|---|---|---|
name | string | 監視する単一フィールド名。 |
names | string[] | 監視する複数フィールド名の配列。 |
defaultValue | `unknown \ | Record<string, unknown>` |
callback | Function | (非推奨)値の変更時に呼ばれるコールバック関数。 |
戻り値
| 呼び出し方 | 戻り値 |
|---|---|
watch("name") | フィールドの現在の値 |
watch(["name", "email"]) | 値の配列 [nameValue, emailValue] |
watch() | 全フィールドのオブジェクト { name: value, ... } |
watch(callback) | { unsubscribe: () => void } |
コード例
単一フィールドの監視
const { register, watch } = useForm({ defaultValues: { name: "" } });
const nameValue = watch("name");
return (
<div>
<input {...register("name")} />
<p>入力値: {nameValue}</p>
</div>
);複数フィールドの監視
const [firstName, lastName] = watch(["firstName", "lastName"]);
return (
<p>
フルネーム: {firstName} {lastName}
</p>
);条件付きレンダリング
const { register, watch } = useForm();
const showEmail = watch("hasEmail");
return (
<form>
<input type="checkbox" {...register("hasEmail")} />
{showEmail && <input {...register("email")} />}
</form>
);全フィールドの監視
const formValues = watch();
console.log(formValues); // { firstName: "...", lastName: "...", ... }重要なルール / 注意事項
defaultValueを指定しない場合、register前の初回レンダリングではundefinedが返される。useFormのdefaultValues指定を推奨。defaultValueとuseFormのdefaultValuesの両方が設定されている場合、defaultValueが優先される。watchはルートレベルの再レンダリングをトリガーする。パフォーマンスが重要な場合はuseWatchフックを検討すること。watchの結果はレンダリングフェーズ用に最適化されており、useEffectの依存配列には適さない。値の変更検知には外部の比較フックを使用すること。- コールバック形式の
watchは非推奨。代わりにsubscribe()を使用すること。
useForm
useForm は React Hook Form の中核となるカスタムフックで、フォーム全体の管理を担う。オプションを受け取り、フォーム操作用のメソッド群を返す。
シグネチャ
useForm<TFieldValues extends FieldValues = FieldValues>(
props?: UseFormProps<TFieldValues>
): UseFormReturn<TFieldValues>オプション
| Name | Type | Default | Description |
|---|---|---|---|
mode | `'onSubmit' \ | 'onBlur' \ | 'onChange' \ |
reValidateMode | `'onChange' \ | 'onBlur' \ | 'onSubmit'` |
defaultValues | `FieldValues \ | () => Promise<FieldValues>` | {} |
values | FieldValues | — | 外部ソースからリアクティブにフォーム値を更新する。外部の状態管理やサーバーデータとの連携に使用。 |
errors | FieldErrors | — | サーバーから返されたエラーでフォームを更新する。 |
resetOptions | KeepStateOptions | — | values や defaultValues が更新された際の状態保持動作を設定する。 |
resolver | Resolver | — | 外部スキーマバリデーションライブラリ(Yup, Zod, Joi, Vest, Ajv など)との統合用。values と errors プロパティを持つオブジェクトを返す必要がある。 |
context | object | — | resolver に注入されるコンテキストオブジェクト。バリデーション時に追加情報を渡す場合に使用。 |
shouldFocusError | boolean | true | バリデーションエラー発生時に最初のエラーフィールドに自動フォーカスするかどうか。 |
shouldUnregister | boolean | false | true にするとアンマウント時にフィールドを自動登録解除し、ネイティブフォームに近い動作になる。値は input 自体に保持される。 |
shouldUseNativeValidation | boolean | false | ブラウザのネイティブ制約バリデーション API を使用する。true の場合、ブラウザ標準のエラーメッセージが表示される。 |
progressive | boolean | false | SSR フレームワークでのプログレッシブエンハンスメントを有効にする。 |
delayError | number | — | エラー表示を遅延させるミリ秒数。ユーザーが入力中にエラーが即座に表示されるのを防ぐ。 |
disabled | boolean | false | フォーム全体と全入力フィールドを無効にする。 |
criteriaMode | `'firstError' \ | 'all'` | 'firstError' |
戻り値
| Name | Type | Description |
|---|---|---|
register | Function | input 要素をフォームに登録する |
unregister | Function | input の登録を解除する |
formState | Object | フォーム全体の状態(dirty, errors, isValid など) |
watch | Function | フィールド値の変更を監視する |
handleSubmit | Function | フォーム送信を処理する |
reset | Function | フォーム全体をリセットする |
resetField | Function | 個別フィールドをリセットする |
setError | Function | エラーを手動で設定する |
clearErrors | Function | エラーをクリアする |
setValue | Function | 単一フィールドの値をプログラム的に設定する |
setValues | Function | 複数フィールドの値を一括で更新する(v7.74+) |
setFocus | Function | 特定フィールドにフォーカスする |
getValues | Function | フォーム値を取得する(再レンダリングなし) |
getFieldState | Function | 個別フィールドの状態を取得する |
trigger | Function | バリデーションを手動で実行する |
resetDefaultValues | Function | デフォルト値を更新し dirty/valid 状態を再計算する(v7.77+) |
control | Object | Controller や useWatch に渡す制御オブジェクト |
Form | Component | フォーム送信を管理するコンポーネント(Beta) |
subscribe | Function | 再レンダリングなしでフォーム状態を購読する |
コード例
import { useForm } from "react-hook-form";
type FormValues = {
firstName: string;
lastName: string;
email: string;
};
function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>({
mode: "onBlur",
defaultValues: {
firstName: "",
lastName: "",
email: "",
},
});
const onSubmit = (data: FormValues) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName", { required: true })} />
{errors.firstName && <span>名前は必須です</span>}
<input {...register("email", { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ })} />
{errors.email && <span>有効なメールアドレスを入力してください</span>}
<input type="submit" />
</form>
);
}非同期デフォルト値
const { register, handleSubmit } = useForm({
defaultValues: async () => {
const response = await fetch("/api/user");
return await response.json();
},
});resolver(Zod)
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
const schema = z.object({
name: z.string().min(1, "名前は必須です"),
age: z.number().min(18, "18歳以上である必要があります"),
});
const { register, handleSubmit } = useForm({
resolver: zodResolver(schema),
});重要なルール / 注意事項
defaultValuesにundefinedを含めないこと。コントロールドコンポーネントのデフォルトと競合する。defaultValuesはキャッシュされる。リセットするにはresetAPI を使用する。shouldUnregister: trueの場合、useEffectでのフォーム値購読はできない。resolverは{ values: {}, errors: {} }の形式でオブジェクトを返す必要がある。mode: 'onChange'はパフォーマンスに影響するため、必要な場合のみ使用する。
useFormContext
深くネストされたコンポーネント構造で、props のバケツリレー(prop drilling)を避けるためのカスタムフック。FormProvider でラップされたコンポーネントツリー内で、フォームメソッドにアクセスできる。
シグネチャ
const methods = useFormContext<TFieldValues>(): UseFormReturn<TFieldValues>前提条件
useFormContext を使用するには、親コンポーネントで FormProvider によるラップが必要。
Return
useForm が返す全てのメソッドとプロパティを返す。
| Name | Type | Description |
|---|---|---|
register | Function | フィールドを登録する |
unregister | Function | フィールドの登録を解除する |
formState | Object | フォームの状態情報 |
watch | Function | フィールド値の変更を監視する |
handleSubmit | Function | フォーム送信を処理する |
reset | Function | フォーム値をリセットする |
resetField | Function | 個別フィールドをリセットする |
setError | Function | エラーを手動で設定する |
clearErrors | Function | バリデーションエラーをクリアする |
setValue | Function | フィールド値を更新する |
setFocus | Function | フィールドにフォーカスする |
getValues | Function | 現在の値を取得する |
getFieldState | Function | フィールドの状態を取得する |
trigger | Function | バリデーションを手動で実行する |
control | Object | フォーム制御オブジェクト |
コード例
基本的な使い方
import { useForm, FormProvider, useFormContext } from "react-hook-form";
// 親コンポーネント
function App() {
const methods = useForm({
defaultValues: { firstName: "", lastName: "" },
});
const onSubmit = (data) => console.log(data);
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<NestedInput />
<button type="submit">送信</button>
</form>
</FormProvider>
);
}
// 子コンポーネント(深くネストされていても使用可能)
function NestedInput() {
const { register } = useFormContext();
return <input {...register("firstName")} />;
}フォーム状態の利用
function SubmitButton() {
const { formState: { isSubmitting, isValid } } = useFormContext();
return (
<button type="submit" disabled={isSubmitting || !isValid}>
{isSubmitting ? "送信中..." : "送信"}
</button>
);
}エラー表示
function ErrorDisplay({ name }) {
const { formState: { errors } } = useFormContext();
const error = errors[name];
if (!error) return null;
return <span role="alert">{error.message}</span>;
}重要なルール
1. FormProvider が必須: useFormContext は FormProvider でラップされたコンポーネントツリー内でのみ動作する。ラップなしで使用すると undefined が返る。 2. useEffect の依存配列に `methods` 全体を入れない: methods オブジェクト全体を useEffect の依存配列に含めると、不要な再レンダリングや無限ループが発生する。必要な個別メソッド(例: reset)を依存配列に入れること。
// NG: methods 全体を依存配列に入れる
const methods = useFormContext();
useEffect(() => {
// ...
}, [methods]); // 無限ループの原因
// OK: 個別メソッドを依存配列に入れる
const { reset } = useFormContext();
useEffect(() => {
reset(data);
}, [reset, data]);3. 型安全性: TypeScript で型パラメータを渡すことで、返されるメソッドに型が適用される。
const { register } = useFormContext<{ firstName: string; lastName: string }>();dev-tools
| Name | Description | Path |
|---|
React Hook Form — FAQs
パフォーマンス
React Hook Form は非制御コンポーネントベースで設計されている。register が ref をキャプチャし、Controller が再レンダリングスコープを管理する。これにより入力時の再レンダリングを最小化し、マウント速度を向上させる。
アクセシブルなエラー表示
<input
{...register("name", { required: true })}
aria-invalid={errors.name ? "true" : "false"}
/>
{errors.name && <span role="alert">This field is required</span>}クラスコンポーネントとの互換性
React Hook Form はフックベースのため、クラスコンポーネントでは直接使用できない。関数コンポーネントでラップし、props 経由でデータを渡す。
フォームリセット方法
| メソッド | 動作 |
|---|---|
HTMLFormElement.reset() | input/select/checkbox の値のみクリア |
react-hook-form の reset() | 全フィールドの値をリセットし、全エラーをクリア |
フォーム値の初期化
// 同期
useForm({ defaultValues: { firstName: "", lastName: "" } })
// 非同期
useForm({ defaultValues: async () => fetch("/api/user").then(res => res.json()) })
// リアクティブ更新(外部データソース)
useForm({ values: externalData, resetOptions: { keepDirtyValues: true } })ref の共有
const { ref, ...rest } = register("test")
<input
{...rest}
ref={(e) => {
ref(e)
myCustomRef.current = e
}}
/>ref なしの登録
useEffect 内で手動登録し、setValue / setError で管理:
useEffect(() => {
register("test")
}, [register])
<input onChange={(e) => setValue("test", e.target.value)} />最初のキー入力で値が消える
value ではなく defaultValue を使用する。React Hook Form は非制御入力が前提。
React Hook Form vs Formik vs Redux Form
| 項目 | React Hook Form | Formik | Redux Form |
|---|---|---|---|
| サイズ | 8.5KB | 15KB | 26.4KB |
| 再レンダリング | 最小限 | 状態変更ごと | Redux 変更ごと |
| API | Hooks | Components + Hooks | Components |
watch vs getValues vs state
| API | 再レンダリング | 用途 |
|---|---|---|
watch | あり(フィールド変更時) | フィールド値に基づく条件付きレンダリング |
getValues | なし | イベントハンドラ内での値取得 |
local state | あり(入力ごと) | 通常の React state 管理 |
条件付きレンダリングとデフォルト値
三項演算子で入力を切り替える場合、一意の key prop を設定して React にコンポーネントの変更を認識させる:
{isA ? <input key="a" {...register("a")} /> : <input key="b" {...register("b")} />}モーダル / タブ内のフォーム
各モーダル/タブに個別のフォームを作成し、送信データをローカル/グローバル state にキャプチャ。最終的に結合して処理する。
Get Started
| Name | Description | Path |
|---|
TypeScript
| Name | Description | Path |
|---|