► React Hook Form V7 is released. If you are planning to upgrade, please read through the Migration Guide to V7.
useForm: Function
useForm
は省略可能な引数もあります。 下記の例は、全てのオプションのデフォルト値を示します。
const { register } = useForm({ mode: 'onSubmit', reValidateMode: 'onChange', defaultValues: {}, resolver: undefined, context: undefined, criteriaMode: "firstError", shouldFocusError: true, shouldUnregister: true, })
type FormInputs = { firstName: string; lastName: string; }; const { register } = useForm<FormInputs>({ mode: 'onSubmit', reValidateMode: 'onChange', defaultValues: {}, resolver: undefined, context: undefined, criteriaMode: "firstError", shouldFocusError: true, shouldUnregister: true, })
mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'
React Native: compatible with Controller
Name | Type | 説明 |
---|---|---|
onSubmit (Default) | string | submit イベントからバリデーションがトリガーされ、 無効な入力は onChange イベントリスナーをアタッチして再度バリデーションを行います。 |
onBlur | string | blur イベントからバリデーションがトリガーされます。 |
onChange | string | 入力の度に change イベントからバリデーションがトリガーされ、複数の再レンダリングが行われます。 非推奨: これをパフォーマンスの悪い習慣と考えてください。 |
onTouched | string | 入力がタッチされるまでバリデーションが発生します。 |
all | string | 検証はblur およびchange イベントでトリガーされます。 警告:onChange モードと同様に、all はパフォ ーマンスに大きな影響を与える可能性があります |
reValidateMode: onChange | onBlur | onSubmit = 'onChange'
React Native: Custom register or using Controller
このオプションを使用すると、エラーのある入力が再度バリデーションされるタイミングを設定することができます。 (デフォルトでは、入力変更時にバリデーションがトリガーされます。) |
defaultValues: Record<string, any> = {}Video
defaultValue/defaultChecked
を使用して input のデフォルト値を設定するか (詳細については React ドキュメントを参照) 、defaultValues
を省略可能な引数として渡してフォーム全体のデフォルト値を設定することができます。
重要: defaultValues
はカスタムフック内にキャッシュされます。 defaultValues
をリセットしたい場合は、 API を使用してください。
注意: defaultValues
で定義された値は defaultValue
として に注入されます。
注意: 手動で register
を適用したフィールドでは React Hook Form に ref
を提供しないため、 手動で登録した input (例: register('test')
) に defaultValues
は自動設定されません。
const { register } = useForm({ defaultValues: { firstName: "bill", lastName: "luo", email: "bluebill1049@hotmail.com", isDeveloper: true } }) <input name="firstName" ref={register} /> // ✅ working version <input name="lastName" ref={() => register({ name: 'lastName' })} /> // ❌ above example does not work with "defaultValues" due to its "ref" not being provided
type Inputs = { firstName: string; lastName: string; email: string; isDeveloper: boolean; } const { register } = useForm<Inputs>({ defaultValues: { firstName: "bill", lastName: "luo", email: "bluebill1049@hotmail.com", isDeveloper: true } }) <input name="firstName" ref={register} /> // ✅ working version <input name="lastName" ref={() => register({ name: 'lastName' })} /> // ❌ above example does not work with "defaultValues" due to its "ref" not being provided
resolver: (values: any, context?: object) => Promise<ResolverResult> | ResolverResult
この関数を使用すると、Yup, Joi、Superstruct などの任意の外部のバリデーションメソッドを実行できます。 実際には、Yup を外部の(スキーマ)バリデーションライブラリとして制限するだけがゴールではありません。 私たちは React Hook Form で動作する多くのバリデーションライブラリをサポートしたいと思っています。 カスタムバリデーションロジックを作成して検証することもできます。
Yup、Joi、Superstructを正式にサポートしています 標準リゾルバー。
npm install @hookform/resolvers
カスタムリゾルバの構築に関する注意:
注意:
values
とerrors
を含むオブジェクトを返していることを確認してください。 デフォルト値は空のオブジェクト{}
である必要があります。注意: 返す
errors
オブジェクトのキーは、フォーム内の input(name
属性)に関連させる必要があります。注意:この関数は カスタムフック内にキャッシュされますが、
context
は 再レンダリングのたびに変更できる可変オブジェクト。注意: ライブラリ自体が特定のフィールドに対してエラーオブジェクトを評価し、 それに応じて再レンダリングをトリガーするため、ユーザーの入力中、一度に一つのフィールドでのみ input の再検証が発生します。
import React from 'react'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from "yup"; const schema = yup.object().shape({ name: yup.string().required(), age: yup.number().required(), }).required(); const App = () => { const { register, handleSubmit } = useForm({ resolver: yupResolver(schema), }); return ( <form onSubmit={handleSubmit(d => console.log(d))}> <input {...register("name")} /> <input type="number" {...register("age")} /> <input type="submit" /> </form> ); };
import React from 'react'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from "yup"; type Inputs = { name: string; age: string; }; const schema = yup.object().shape({ name: yup.string().required(), age: yup.number().required(), }).required(); const App = () => { const { register, handleSubmit } = useForm<Inputs>({ resolver: yupResolver(schema), // yup, joi and even your own. }); return ( <form onSubmit={handleSubmit(d => console.log(d))}> <input {...register("name")} /> <input type="number" {...register("age")} /> <input type="submit" /> </form> ); };
shouldUnregister: boolean = true
CodeSandbox
デフォルトでは、入力が削除されると、React Hook FormはMutationObserver
を使用して、マウント解除された入力を検出および登録解除
します。ただし、shouldUnregister
をfalse
に設定して、マウント解除による入力状態の損失を防ぐことができます。
true | false | |
Can you unregister an input? | ✅ | ❌ |
Value remains when input unmounts? | ❌ | ✅ |
Is form state updated? eg: isValid, isDirty, touched | ✅ | ❌ you will need to clear manually |
object | このコンテキストオブジェクトは、 |
firstError | all | デフォルトの設定である このオプションを |
boolean = true | デフォルトでは、ユーザーがフォームを送信してそのフォームにエラーが含まれている時、 エラーのある最初のフィールドがフォーカスされます。 注意: |
♦
register: (Ref, RegisterOptions?) => voidReact Native: Custom register or using Controller
このメソッドを使用すると、input/select の Ref
とバリデーションルールを React Hook Form に登録 (register
) することができます。
バリデーションルールは全て HTML 標準に基づいており、カスタムバリデーションも可能です。
重要: name
属性は必須かつユニークです。 input の name 属性はドット記法およびブラケット記法もサポートしているため、 ネストされたフォームフィールドを簡単に作成することができます。例は下記の通りです:
Input Name | フォームの送信結果 |
---|---|
name="firstName" | { firstName: 'value'} |
name="name.firstName" | { name: { firstName: 'value' } } |
name="name.firstName[0]" | { name: { firstName: [ 'value' ] } } |
arrays/array
フィールドを使用する場合 、input の name 属性を name[index]
のように割り当てることができます。フィールド配列の例をご覧ください。
カスタム登録
また、input を手動で登録 (manual register
) することもできます。 これは、カスタムコンポーネントを操作していて Ref
にアクセスできない場合に便利です。 React Native や react-select のようなカスタムコンポーネントを使用している場合がこれに該当します。
カスタム登録を使用すると、 input の ref は登録されていないため、 で入力値を更新する必要があります。
register('firstName', { required: true, min: 8 })
注意: 値の更新中に、カスタム登録した input で再レンダリングをトリガーしたい場合は、 登録した input に type 属性を指定する必要があります。
register({ name: 'firstName', type: 'custom' }, { required: true, min: 8 })
Nota: multiple radio inputs with the same name, you want to register the validation to the last input so the hook understand validate them as a group at the end.
Name | 説明 | コードの例 |
---|---|---|
ref React.RefObject | React element ref |
|
required boolean | Boolean の値。true の場合、フォームを送信する前に入力値が必須であることを示します。errors オブジェクトにエラーメッセージを返す文字列を割り当てることができます。 |
|
maxLength
| input が受け付ける最大文字数。 |
|
minLength
| input が取りうる妥当と判断される最小文字数。 |
|
max
| input が受け付ける最大数。 |
|
min
| input が取りうる妥当と判断される最小数。 |
|
pattern
| input の内容が一致する必要がある正規表現。 |
|
validate Function | Object | 引数として、単一のバリデーションを行うためにはコールバック関数を渡すことができ、複数のバリデーションを行うためにはコールバック関数のオブジェクトを渡すことができます。 (例を参照) |
|
valueAsNumber:boolean | Returns a Number normally. If something goes wrong Note: |
|
valueAsDate:boolean | Returns a Date normally. If something goes wrong Note: |
|
setValueAs:<T>(value: any) => T | Return input value by running through the function. Note: |
|
unregister: (name: string | string[]) => void
このメソッドでは、単一の input または input の配列に unregister
を適用することができます。 これは、 useEffect
でカスタム登録として input を登録 (register
) し、 コンポーネントのアンマウント後に登録を解除する場合に便利です。
注意: input を登録解除 (unregister
) すると、 その値は送信されたフォームデータに含まれなくなります。
import React, { useEffect } from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, handleSubmit, unregister } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstName" ref={register} /> <input name="lastName" ref={register} /> <button type="button" onClick={() => unregister("lastName")}>unregister</button> <input type="submit" /> </form> ); }
import React, { useEffect } from "react"; import { useForm } from "react-hook-form"; interface IFormInputs { firstName: string; lastName?: string; } export default function App() { const { register, handleSubmit, unregister } = useForm<IFormInputs>(); const onSubmit = (data: IFormInputs) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstName" ref={register} /> <input name="lastName" ref={register} /> <button type="button" onClick={() => unregister("lastName")}>unregister</button> <input type="submit" /> </form> ); };
errors: Record<string, object>
オブジェクトには、各 input のフォームのエラーまたはエラーメッセージが含まれています。
Name | Type | 説明 |
---|---|---|
type | string | Error Type. eg: required, min, max, minLength |
types | Record<{ string, string | boolean }> | これは、単一のフィールドで複数のエラーを返す必要がある、 パスワードのルールのような input のバリデーションに役立ちます。 この機能を有効にするには、 criteriaMode 'all' を設定してください。 |
message | string | React.ReactElement | メッセージはデフォルトでは空文字です。ただし、バリデーションとエラーメッセージで登録するとエラーメッセージが返されます。 |
ref | React.Ref | input 要素の参照。 |
注意: を使用すると、エラー状態の処理に役立ちます。
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, formState: { errors }, handleSubmit } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("singleErrorInput", { required: true })} /> {errors.singleErrorInput && "Your input is required"} {/* refer to the type of error to display message accordingly */} <input {...register("multipleErrorInput", { required: true, maxLength: 50 })} /> {errors.multipleErrorInput?.type === "required" && "Your input is required"} {errors.multipleErrorInput?.type === "maxLength" && "Your input exceed maxLength"} {/* register with validation */} <input type="number" {...register("numberInput", { min: 50 })} /> {errors.numberInput && "Your input required to be more than 50"} {/* register with validation and error message */} <input {...register("errorMessage", { required: "This is required" })} /> {errors.errorMessage?.message} <input type="submit" /> </form> ); }
import * as React from 'react' import { useForm } from "react-hook-form"; interface IFormInputs { singleErrorInput: string multipleErrorInput: string numberInput: string } function App() { const { register, formState: { errors }, handleSubmit } = useForm<IFormInputs>(); const onSubmit = (data: IFormInputs) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <label>Error</label> <input {...register("singleErrorInput", { required: true })} /> {errors.singleErrorInput && <p>Your input is required</p>} <label>Error with type check</label> <input {...register("multipleErrorInput", { required: true, minLength: 5 })} /> {errors.multipleErrorInput?.type === "required" && ( <p>Your input is required</p> )} {errors.multipleErrorInput?.type === "minLength" && ( <p>Your input must be larger then 3 characters</p> )} <label>Error with value</label> <input type="number" {...register("numberInput", { min: 50 })} /> {errors.numberInput && <p>Your input required to be more than 50</p>} <input type="submit" /> </form> ); }
import React from "react"; import { useForm } from "react-hook-form"; type Inputs = { a: number; b: string; c: Date; d: { e: string; }; f: { g: number[]; h: string[]; i: { j: string }[]; }; k: any; l: any[]; m: unknown; n: unknown[]; o: object; p: object[]; q: { r: any; s: { t: any[]; u: unknown; v: object; }[]; w: Date[]; x: { y: { z: object[]; }; }; }; }; export default function App() { const { formState: { errors } } = useForm<Inputs>(); console.log(errors?.a?.message); console.log(errors?.b?.message); console.log(errors?.c?.message); console.log(errors?.d?.e?.message); console.log(errors?.f?.g && errors.f.g[0] && errors.f.g[0].message ); console.log(errors?.f?.h && errors.f.h[0] && errors.f.h[0].message ); console.log( errors?.f?.i && errors?.f?.i[0] && errors.f.i[0].j && errors.f.i[0].j.message ); console.log(errors?.k?.message); console.log(errors?.l?.message); console.log(errors?.m?.message); console.log(errors?.n && errors.n[0] && errors.n[0].message); console.log(errors?.o?.message); console.log(errors?.p && errors.p[0] && errors.p[0].message); console.log(errors?.q?.r?.message); console.log( errors?.q?.s && errors.q.s[0] && errors.q.s[0].t.message ); console.log( errors?.q?.s && errors.q.s[0] && errors.q.s[0].u && errors.q.s[0].u.message ); console.log( errors?.q?.s && errors.q.s[0] && errors.q.s[0].v && errors.q.s[0].v.message ); console.log(errors?.q?.w && errors.q.w[0] && errors.q.w[0].message ); console.log( errors?.q?.x?.y?.z && errors.q.x.y.z[0] && errors.q.x.y.z[0].message ); return <form />; }
watch: (names?: string | string[]) => anyVideo
これは指定された input/inputs を監視し、その値を返します。
defaultValue
が定義されていない場合、watch
の初回のレンダリングはregister
の前に呼び出されるためundefined
を返しますが、 第2引数としてdefaultValue
を設定して値を返すことができます。ただし、引数として
useForm
でdefaultValues
が初期化された場合、 初回のレンダリングはdefaultValues
で指定された値を返します。
Type | 説明 | 例 | Return |
---|---|---|---|
string | input の値を name から監視します (lodash の get 関数に似ています) | watch('inputName') watch('inputName', 'value') | any |
string[] | 複数の input を監視します | watch(['inputName1']) watch(['field1'], { field1: '1' }) | { [key:string] : any } |
undefined | 全ての input を監視します | watch() watch(undefined, { field: '1' }) | { [key:string] : any } |
import React from "react"; import { useForm } from "react-hook-form"; function App() { const { register, watch, errors, handleSubmit } = useForm(); const watchShowAge = watch("showAge", false); // you can supply default value as second argument const watchAllFields = watch(); // when pass nothing as argument, you are watching everything const watchFields = watch(["showAge", "number"]); // you can also target specific fields by their names const onSubmit = data => console.log(data); return ( <> <form onSubmit={handleSubmit(onSubmit)}> <input type="checkbox" name="showAge" ref={register} /> {/* based on yes selection to display Age Input*/} {watchShowAge && <input type="number" name="age" ref={register({ min: 50 })} />} <input type="submit" /> </form> </> ); }
import React from "react"; import { useForm } from "react-hook-form"; interface IFormInputs { name: string showAge: boolean age: number } function App() { const { register, watch, errors, handleSubmit } = useForm<IFormInputs>(); const watchShowAge = watch("showAge", false); // you can supply default value as second argument const watchAllFields = watch(); // when pass nothing as argument, you are watching everything const watchFields = watch(["showAge", "number"]); // you can also target specific fields by their names const onSubmit = (data: IFormInputs) => console.log(data); return ( <> <form onSubmit={handleSubmit(onSubmit)}> <input name="name" ref={register({ required: true, maxLength: 50 })} /> <input type="checkbox" name="showAge" ref={register} /> {/* based on yes selection to display Age Input*/} {watchShowAge && ( <> <input type="number" name="age" ref={register({ min: 50 })} /> </> )} <input type="submit" /> </form> </> ); }
import React from "react"; import { useForm } from "react-hook-form"; type Inputs = { key1: string; key2: number; key3: { key1: number; key2: boolean; }; }; export default function App(props) { const { watch } = useForm<FormValues>; watch(); // function watch(): FormValues watch({ nest: true }); // function watch(option: { nest: boolean; }): FormValues watch("key1"); // function watch<"key1">(field: "key1", defaultValue?: string | undefined): string watch("key1", "test"); // function watch<"key1">(field: "key1", defaultValue?: string | undefined): string watch("key1", true); // ❌: type error watch("key3.key1"); // function watch<unknown>(field: string, defaultValue?: unknown): unknown watch("key3.key1", 1); // function watch<1>(field: string, defaultValue?: 1 | undefined): number watch("key3.key1", "test"); // function watch<"key3.key1", "test">(field: "key3.key1", defaultValue?: string | undefined): string watch("key3.key2", true); // function watch<true>(field: string, defaultValue?: true | undefined): boolean watch(["key1", "key2"]); // function watch<"key1" | "key2">(fields: ("key1" | "key2")[], defaultValues?: DeepPartial<Pick<FormValues, "key1" | "key2">> | undefined): Pick<FormValues, "key1" | "key2"> watch(["key1", "key2"], { key1: "test" }); // function watch<"key1" | "key2">(fields: ("key1" | "key2")[], defaultValues?: DeepPartial<Pick<FormValues, "key1" | "key2">> | undefined): Pick<FormValues, "key1" | "key2"> watch(["key1", "key2"], { key1: "test", key2: true }); // ❌: type error watch(["key1", "key3.key1"], { key1: "string" }); // function watch(fields: string[], defaultValues?: DeepPartial<FormValues> | undefined): DeepPartial<FormValues> watch(["key1", "key3.key1"], { test: "string" }); // ❌: type error watch<string, FormData["key3"]["key1"]>("key3.key1"); // => string watch<string, FormData["key3"]["key2"]>("key3.key2"); // => string return <form />; }
handleSubmit:
((data: Object, e?: Event) => void, (errors: Object, e?: Event) => void) => Function
この関数は、フォームバリデーションに成功するとフォームデータを渡します。また、リモートで呼び出すこともできます。
handleSubmit(onSubmit)()
注意: 非同期バリデーションのための async
関数を渡すことができます。例:
handleSubmit(async (data) => await fetchAPI(data))
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, handleSubmit } = useForm(); const onSubmit = (data, e) => console.log(data, e); const onError = (errors, e) => console.log(errors, e); return ( <form onSubmit={handleSubmit(onSubmit, onError)}> <input name="firstName" ref={register} /> <input name="lastName" ref={register} /> <button type="submit">Submit</button> </form> ); }
import React from "react"; import { useForm, SubmitHandler } from "react-hook-form"; type FormValues = { firstName: string; lastName: string; email: string; }; export default function App() { const { register, handleSubmit } = useForm<FormValues>(); const onSubmit: SubmitHandler<FormValues> = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstName" ref={register} /> <input name="lastName" ref={register} /> <input name="email" type="email" ref={register} /> <input type="submit" /> </form> ); }
reset: (values?: Record<string, any>, omitResetState?: Record<string, boolean>) => void
この関数は、フォーム内のフィールドの値とエラーをリセット (reset
) します。omitResetState
を指定することにより、次のことができます。 特定の状態のみをリセットします。 省略可能な引数として values
を渡すと、 割り当てられたデフォルト値でフォームをリセットできます。
注意: ref
を公開しない React-Select
のような制御されたコンポーネントの場合は、 手動で入力値をリセットするために を使用するか、 コンポーネントを使用して制御されたコンポーネントをラップする必要があります。
注意: Controller
コンポーネントの値をリセットするには、useForm
に defaultValues
を指定する必要があります。
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, handleSubmit, reset } = useForm(); const onSubmit = (data, e) => {}; useEffect(async () => { const result = await fetch('./api/formValues.json'); // result: { firstName: 'test', lastName: 'test2' } reset(result); // asynchronously reset your form values }, [reset]) return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstName" ref={register({ required: true })} /> <input name="lastName" ref={register} /> <input type="reset" /> // standard reset button <input type="button" onClick={() => reset({ firstName: "bill" }); }} /> // reset form with values <input type="button" onClick={() => { reset({ firstName: "bill" }, { errors: true, // errors will not be reset dirtyFields: true, // dirtyFields will not be reset isDirty: true, // dirty will not be reset isSubmitted: false, touched: false, isValid: false, submitCount: false, }); }} /> </form> ); }
import React from "react"; import { useForm } from "react-hook-form"; interface UseFormInputs { firstName: string lastName: string } export default function Form() { const { register, handleSubmit, reset, errors } = useForm<UseFormInputs>(); const onSubmit = (data: UseFormInputs) => { console.log(data) }; return ( <form onSubmit={handleSubmit(onSubmit)}> <label>First name</label> <input name="firstName" ref={register({ required: true })} /> <label>Last name</label> <input name="lastName" ref={register} /> <input type="submit" /> <input type="reset" value="Standard Reset Field Values" /> <input type="button" onClick={() => reset()} value="Custom Reset Field Values & Errors" /> </form> ); }
setError:
(name: string, error: { type?: string, types?: object, message?: string, shouldFocus?: boolean }) => void
単一または複数の input のエラーを手動で設定できます。
このメソッドは、入力された場合、関連する入力エラーを永続化しません 検証に合格します。
入力フィールドに関連付けられていないエラーを設定します 永続化し、
clearErrors
で手動で削除する必要があります。handleSubmit
関数の実行時に役立ちます。 非同期検証後にユーザーにエラーフィードバックを提供したい。
import React from "react"; import { useForm } from "react-hook-form"; const App = () => { const { register, handleSubmit, setError, errors } = useForm(); const onSubmit = data => { console.log(data) }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="username" onChange={() => { setError("username", { type: "manual", message: "Dont Forget Your Username Should Be Cool!" }); }} ref={register} /> {errors.username && <p>{errors.username.message}</p>} <input type="submit" /> </form> ); };
import * as React from "react"; import { useForm } from "react-hook-form"; type FormInputs = { username: string; }; const App = () => { const { register, handleSubmit, setError, errors } = useForm<FormInputs>(); const onSubmit = (data: FormInputs) => { console.log(data) }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="username" onChange={() => { setError("username", { type: "manual", message: "Dont Forget Your Username Should Be Cool!" }); }} ref={register} /> {errors.username && <p>{errors.username.message}</p>} <input type="submit" /> </form> ); };
clearErrors: (name?: string | string[]) => void
undefined
: 全てのエラーをリセットstring
: 単一のエラーをリセットstring[]
: 複数のエラーをリセット
import * as React from "react"; import { useForm } from "react-hook-form"; const App = () => { const { register, errors, handleSubmit, clearErrors } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstName" ref={register({ required: true })} /> <input name="lastName" ref={register({ required: true })} /> <input name="username" ref={register({ required: true })} /> <button type="button" onClick={() => clearErrors("firstName")}> Clear First Name Errors </button> <button type="button" onClick={() => clearErrors(["firstName", "lastName"])} > Clear First and Last Name Errors </button> <button type="button" onClick={() => clearErrors()}> Clear All Errors </button> <input type="submit" /> </form> ); };
import * as React from "react"; import { useForm } from "react-hook-form"; import "./styles.css"; type FormInputs = { firstName: string; lastName: string; username: string; }; const App = () => { const { register, errors, handleSubmit, clearErrors } = useForm<FormInputs>(); const onSubmit = (data: FormInputs) => { console.log(data) }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstName" ref={register({ required: true })} /> <input name="lastName" ref={register({ required: true })} /> <input name="username" ref={register({ required: true })} /> <button type="button" onClick={() => clearErrors("firstName")}> Clear First Name Errors </button> <button type="button" onClick={() => clearErrors(["firstName", "lastName"])} > Clear First and Last Name Errors </button> <button type="button" onClick={() => clearErrors()}> Clear All Errors </button> <input type="submit" /> </form> ); };
setValue: (name: string, value: any, config?: Object) => void
この関数を使用すると、input/select の値を動的に設定できます。 setValue は不要な再レンダリングを避けようとしますが、 以下の条件でのみ再レンダリングをトリガーします。
値の更新によってエラーがトリガーされるとき
値の更新によってエラーが修正されるとき
setValue が初めて実行され、 formState の
isDirty
が true に設定されたとき
注意: このメソッドを呼び出すことで、formState
は input の name
を touched
にプッシュします。
shouldValidate
を true
に設定すると、 フィールドのバリデーションがトリガーされます。
setValue('name', 'value', { shouldValidate: true })
フィールドをダーティに設定するために、shouldDirty
パラメータをtrue
に設定することもできます。
setValue('name', 'value', { shouldDirty: true })
import * as React from "react"; import { useForm } from "react-hook-form"; const App = () => { const { register, handleSubmit, setValue } = useForm(); const onSubmit = data => { console.log(data) }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstName" ref={register} /> <input name="lastName" ref={register} /> <button onClick={() => setValue("firstName", "Bill")}> Set First Name Value </button> <button onClick={() => setValue("lastName", "Luo", { shouldValidate: true, shouldDirty: true }) } > Set Last Name </button> <input type="submit" /> </form> ); };
import * as React from "react"; import { useForm } from "react-hook-form"; type FormInputs = { firstName: string lastName: string } const App = () => { const { register, handleSubmit, setValue } = useForm<FormInputs>(); const onSubmit = (data: FormInputs) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="firstName" ref={register} /> <input name="lastName" ref={register} /> <button onClick={() => setValue("firstName", "Bill")}> Set First Name Value </button> <button onClick={() => setValue("lastName", "Luo", { shouldValidate: true, shouldDirty: true }) } > Set Last Name </button> <input type="submit" /> </form> ); };
import React from "react"; import { useForm } from "react-hook-form"; type FormValues = { string: string; number: number; object: { number: number; boolean: boolean; }; array: { string: string; boolean: boolean; }[]; }; export default function App() { const { setValue } = useForm<FormValues>(); setValue("string", "test"); // function setValue<"string", string>(name: "string", value: string, shouldValidate?: boolean | undefined): void setValue("number", 1); // function setValue<"number", number>(name: "number", value: number, shouldValidate?: boolean | undefined): void setValue("number", "error"); return <form />; }
getValues: (payload?: string | string[]) => Object
この関数は、フォームの値を読み取るのに役立ちます。違いwatch
の間はgetValues
はトリガーされません 入力の変更を再レンダリングまたはサブスクライブします。機能は次のとおりです。
getValues()
:フォームの値全体を読み取ります。getValues('test'
:個々の入力値を読み取りますname。getValues(['test', 'test1'])
:複数の入力を読み取りますname。
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, getValues } = useForm(); return ( <form> <input name="test" ref={register} /> <input name="test1" ref={register} /> <button type="button" onClick={() => { const values = getValues(); // { test: "test-input", test1: "test1-input" } const singleValue = getValues("test"); // "test-input" const multipleValues = getValues(["test", "test1"]); // { test: "test-input", test1: "test1-input" } }} > Get Values </button> </form> ); }
import React from "react"; import { useForm } from "react-hook-form"; type FormInputs = { test: string test1: string } export default function App() { const { register, getValues } = useForm<FormInputs>(); return ( <form> <input name="test" ref={register} /> <input name="test1" ref={register} /> <button type="button" onClick={() => { const values = getValues(); // { test: "test-input", test1: "test1-input" } const singleValue = getValues("test"); // "test-input" const multipleValues = getValues(["test", "test1"]); // { test: "test-input", test1: "test1-input" } }} > Get Values </button> </form> ); }
import React from "react"; import { useForm } from "react-hook-form"; // Flat input values type Inputs = { key1: string; key2: number; key3: boolean; key4: Date; }; export default function App() { const { register, getValues } = useForm<Inputs>(); getValues(); return <form />; } // Nested input values type Inputs1 = { key1: string; key2: number; key3: { key1: number; key2: boolean; }; key4: string[]; }; export default function Form() { const { register, getValues } = useForm<Inputs1>(); getValues(); // function getValues(): Record<string, unknown> getValues("key1"); // function getValues<"key1", unknown>(payload: "key1"): string getValues("key2"); // function getValues<"key2", unknown>(payload: "key2"): number getValues("key3.key1"); // function getValues<"key3.key1", unknown>(payload: "key3.key1"): unknown getValues<string, number>("key3.key1"); // function getValues<string, number>(payload: string): number getValues<string, boolean>("key3.key2"); // function getValues<string, boolean>(payload: string): boolean getValues("key4"); // function getValues<"key4", unknown>(payload: "key4"): string[] return <form />; }
trigger: (payload?: string | string[]) => Promise<boolean>
フォームで input/select のバリデーションを手動でトリガーします。
注意: バリデーションが失敗すると、errors
オブジェクトが更新されます。
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, trigger, errors } = useForm(); return ( <form> <input name="firstName" ref={register({ required: true })} /> <input name="lastName" ref={register({ required: true })} /> <button type="button" onClick={() => { trigger("lastName"); }}>Trigger</button> <button type="button" onClick={() => { trigger(["firstName", "lastName"]); }}>Trigger Multiple</button> <button type="button" onClick={() => { trigger(); }}>Trigger All</button> <button type="button" onClick={async () => { const result = await trigger("lastName"); if (result) { console.log("valid input") } }} > Trigger Result </button> </form> ); }
import React from "react"; import { useForm } from "react-hook-form"; type FormInputs = { firstName: string lastName: string } export default function App() { const { register, trigger, errors } = useForm<FormInputs>(); return ( <form> <input name="firstName" ref={register({ required: true })} /> <input name="lastName" ref={register({ required: true })} /> <button type="button" onClick={() => { trigger("lastName"); }}>Trigger</button> <button type="button" onClick={() => { trigger(["firstName", "lastName"]); }}>Trigger Multiple</button> <button type="button" onClick={() => { trigger(); }}>Trigger All</button> <button type="button" onClick={async () => { const result = await trigger("lastName"); if (result) { console.log("valid input") } }} > Trigger Result </button> </form> ); }
control: Object
このオブジェクトは、 React Hook Form の Controller コンポーネント用に作成され、 React Hook Form に制御されたコンポーネントを登録するためのメソッドが含まれています。
import React from "react"; import { useForm, Controller } from "react-hook-form"; function App() { const { control } = useForm(); return ( <Controller as={<input />} name="firstName" control={control} defaultValue="" /> ); }
import React from "react"; import { useForm, Controller } from "react-hook-form"; import { TextField } from "@material-ui/core"; type FormInputs = { firstName: string } function App() { const { control, handleSubmit } = useForm<FormInputs>(); const onSubmit = (data: FormInputs) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller as={TextField} name="firstName" control={control} defaultValue="" /> <input type="submit" /> </form> ); }
formState: Object
このオブジェクトには、フォームの状態に関する情報が含まれています。
重要: formState
はレンダリングパフォーマンスの改善のために Proxy にラップされているので、状態の更新を有効にするには、render
前に formState
を呼び出すか、読み込む必要があります。 この再レンダリング機能の削減機能は、Webプラットフォームにのみ適用されます。 React NativeでのProxy
のサポートについて 。
Name | Type | 説明 |
---|---|---|
isDirty | boolean | ユーザが入力操作した後 true に設定します。 |
dirtyFields | object | ユーザーが変更したフィールドの一意の Set オブジェクト。 |
touched | object | 操作された全ての input の name の配列。 |
isSubmitted | boolean | ユーザーがフォームを送信した後 true に設定します。フォームの送信後、その状態は、resetメソッドで呼び出されるまで送信されたままになります。 |
isSubmitSuccessful | boolean | フォームが正常に送信されたことを示します。 |
isSubmitting | boolean | フォームの送信中は true に設定し、 フォームの送信後は false に設定します。 |
submitCount | number | フォームの送信回数。 |
isValid | boolean | エラーがない場合は true に設定します。 Note: |
isValidating | boolean | 検証中にtrue に設定します。 |
errors | object | An object with field errors. |
import React from "react"; import { useForm } from "react-hook-form"; export default function App() { const { register, handleSubmit, errors, // Read the formState before render to subscribe the form state through Proxy formState: { isDirty, isSubmitting, touched, submitCount }, } = useForm(); const onSubmit = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="test" ref={register} /> <input type="submit" /> </form> ); }
import React from "react"; import { useForm } from "react-hook-form"; type FormInputs = { test: string } export default function App() { const { register, handleSubmit, errors, // Read the formState before render to subscribe the form state through the Proxy formState: { isDirty, isSubmitting, touched, submitCount }, } = useForm<FormInputs>(); const onSubmit = (data: FormInputs) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="test" ref={register} /> <input type="submit" /> </form> ); }
Controller: Component
React Hook Form は、非制御コンポーネントとネイティブ HTML input をサポートしていますが、 React-Select や AntD 、 MUIなどの外部の制御された UI コンポーネントライブラリと組み合わせての使用を避けることは難しいです。 このラッパーコンポーネントにより、制御されたコンポーネントと組み合わせて簡単に使用できるようになります。
Controllerコンポーネントへ渡す全ての props は、as
prop で指定した Component インスタンスに転送されます。 つまり、label
prop を必要とするカスタム Switch
コンポーネントがあるとします。 この label
prop を Controller コンポーネントに直接渡すことができます。name
prop は、主に後でフォームから値にアクセスするために使用されます。
Name | Type | 必須 | 説明 |
---|---|---|---|
name | string | ✓ | input のユニークな name 。 |
control | Object | ✓ | control オブジェクトは useForm から呼び出されます。 ただし、 FormContext を使用している場合は省略できます。 |
as | React.ElementType | コントローラーはonChange 、onBlur を挿入しますvalue をコンポーネントにプロップします。
| |
render | Function | これはレンダリングプロップ。 React要素を返し、次の機能を提供する関数 イベントと値をコンポーネントにアタッチします。これにより、 非標準の小道具で外部制御コンポーネントと統合する 名前:onChange 、onBlur およびvalue 。
| |
as | React.ElementType | string | ✓ | 制御されたコンポーネント。 例: as="input" または as={<TextInput />} |
defaultValue | any | 非制御コンポーネントの defaultValue と同じですが、 boolean 値を指定すると、チェックボックスの input として扱われます。注意: 注意: フォーム内でデフォルト値を引数として | |
rules | Object | register によるバリデーションルール。
| |
onFocus | () => void | このコールバック関数により、エラーが発生した場合にカスタムフックが入力フィールドにフォーカスさせることができます。 この関数は、React と React-Native どちらでも、フォーカスできるコンポーネントであれば適用可能です。 こちらの MUI を使用した実装例を参考にしてください。 |
import React from "react"; import ReactDatePicker from "react-datepicker"; import { TextField } from "@material-ui/core"; import { useForm, Controller } from "react-hook-form"; function App() { const { handleSubmit, control } = useForm(); return ( <form onSubmit={handleSubmit(data => console.log(data))}> <Controller as={TextField} name="TextField" control={control} defaultValue="" /> <Controller control={control} name="ReactDatepicker" render={({ onChange, onBlur, value }) => ( <ReactDatePicker onChange={onChange} onBlur={onBlur} selected={value} /> )} /> <input type="submit" /> </form> ); }
import React from "react"; import ReactDatePicker from "react-datepicker"; import { TextField } from "@material-ui/core"; import { useForm, Controller } from "react-hook-form"; type FormValues = { TextField: string; ReactDatepicker: string; } function App() { const { handleSubmit, control } = useForm<FormValues>(); return ( <form onSubmit={handleSubmit(data => console.log(data))}> <Controller as={TextField} name="TextField" control={control} defaultValue="" /> <Controller control={control} name="ReactDatepicker" render={({ onChange, onBlur, value }) => ( <ReactDatePicker onChange={onChange} onBlur={onBlur} selected={value} /> )} /> <input type="submit" /> </form> ); }
useController: (arguments: UseControllerProps) => { field: object, meta: object }
このカスタムフックは Controller
を動かし、共有するものです。Controller
と同じプロップスやメソッドを使用しています。これは便利なことに 再利用可能なControlled入力を作成し、Controller
は ページやフォームにドロップするための柔軟なオプションです。
このフックの の引数を共有しています。as
と 以外は同じ引数を共有しています。レンダリング
。
Object Name | Name | Type | 説明 |
---|---|---|---|
field | onChange | (value: any) => void | A function which send value to hook form and should be assigned with |
onBlur | (value: any) => void | A function which send value to hook form and should be assigned with | |
value | unknown | The value of this controlled component. | |
ref | |||
Assign | |||
meta | invalid | boolean | Invalid state for current input. |
isTouched | boolean | Touched state for current controlled input. | |
isDirty | boolean | Dirty state for current controlled input. |
import React from "react"; import { TextField } from "@material-ui/core"; import { useController, control } from "react-hook-form"; function Input({ control, name }) { const { field: { ref, ...inputProps }, meta: { invalid, isTouched, isDirty }, } = useController({ name, control, rules: { required: true }, defaultValue: "", }); return <TextField {...inputProps} inputRef={ref} />; } function App() { const { control } = useForm(); return <Input name="firstName" control={control} />; }
import * as React from "react"; import { useForm, useController } from "./src"; function Input(props) { const { field, meta } = useController(props); return ( <div> <input {...field} placeholder={props.name} /> <p>{meta.isTouched && "Touched"}</p> <p>{meta.isDirty && "Dirty"}</p> <p>{meta.invalid ? "invalid" : "valid"}</p> </div> ); } export default function App() { const { handleSubmit, control } = useForm({ defaultValues: { FirstName: "" }, mode: "onChange" }); const onSubmit = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Input control={control} name="FirstName" rules={{ required: true }} /> <input type="submit" /> </form> ); }
ErrorMessage: Component
関連する input のエラーメッセージを表示するためのシンプルなコンポーネント。
npm install @hookform/error-message
Name | Type | 必須 | 説明 |
---|---|---|---|
name | string | ✓ | 関連するフィールド名 |
errors | object | React Hook Form の errors オブジェクト | |
message | string | React.ReactElement | インラインエラーメッセージ。 | |
as | React.ElementType | string | ラッパーコンポーネント、または HTML タグ。 例: as="span" または as={<Text />} | |
render | ({ message: string | React.ReactElement, messages?: Object}) => any | これは、単一または複数のエラーメッセージをレンダリングするための render prop です。 注意: |
import React from "react"; import { useForm } from "react-hook-form"; import { ErrorMessage } from '@hookform/error-message'; export default function App() { const { register, errors, handleSubmit } = useForm(); const onSubmit = data => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="singleErrorInput" ref={register({ required: "This is required." })} /> <ErrorMessage errors={errors} name="singleErrorInput" /> <ErrorMessage errors={errors} name="singleErrorInput" render={({ message }) => <p>{message}</p>} /> <input type="submit" /> </form> ); }
import React from "react"; import { useForm } from "react-hook-form"; import { ErrorMessage } from '@hookform/error-message'; interface FormInputs { singleErrorInput: string } export default function App() { const { register, formState: { errors }, handleSubmit } = useForm<FormInputs>(); const onSubmit = (data: FormInputs) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register("singleErrorInput", { required: "This is required." })} /> <ErrorMessage errors={errors} name="singleErrorInput" /> <ErrorMessage errors={errors} name="singleErrorInput" render={({ message }) => <p>{message}</p>} /> <input type="submit" /> </form> ); }
useFormContext: Function
フォームコンテキストは、コンポーネントツリーに深くネストされた input があり、 メソッドを props
として深く渡すことが苦痛になる場合の問題を解決することを目的としています。
Return
This hook will return all the useForm return methods and props.
const methods = useForm() <FormProvider {...methods} /> // all the useForm return props const methods = useFormContext() // retrieve those props
フォームが FormProvider
でラップされると、 ラップされた子コンポーネントで useFormContext
を使用して function
を呼び出すことができます。
注意: useFormContext
を呼び出すと全ての useForm
フック関数が得られます。
Rules
You need to wrap your form with the FormProvider
component for useFormContext
to work properly.
Examples
import React from "react"; import { useForm, FormProvider, useFormContext } from "react-hook-form"; export default function App() { const methods = useForm(); const onSubmit = data => console.log(data); return ( <FormProvider {...methods} > // pass all methods into the context <form onSubmit={methods.handleSubmit(onSubmit)}> <NestedInput /> <input type="submit" /> </form> </FormProvider> ); } function NestedInput() { const { register } = useFormContext(); // retrieve all hook methods return <input {...register("test")} />; }
useWatch:
({ control?: Control, name?: string, defaultValue?: unknown, disabled?: boolean }) => object
watch
APIと同じ機能を共有しますが、これは コンポーネントレベルで再レンダリングを分離し、結果的に アプリケーションのパフォーマンスが向上します。
Props
Name | Type | 説明 |
---|---|---|
name | string | string[] | undefined | 関連するフィールド名 |
control | Object | control オブジェクトは useForm から呼び出されます。 ただし、 FormContext を使用している場合は省略できます。 |
defaultValue | unknown | default value for Note: the first render will always return |
disabled | boolean = false | Option to disable the subscription. |
exact | boolean = false | This prop will enable an exact match for input name subscriptions. |
Return
例 | Return |
---|---|
useWatch('inputName') | unknown |
useWatch(['inputName1']) | unknown[] |
useWatch() | {[key:string]: unknown} |
Rules
The initial return value from
useWatch
will always return what's inside ofdefaultValue
ordefaultValues
fromuseForm
.The only difference between
useWatch
andwatch
is at the root (useForm
) level or the custom hook level update.useWatch
's execution order matters, which means if you update a form value before the subscription is in place, then the value updated will be ignored.setValue('test', 'data'); useWatch({ name: 'test' }); // ❌ subscription is happened after value update, no update received useWatch({ name: 'example' }); // ✅ input value update will be received and trigger re-render setValue('example', 'data');
useWatch
's result is optimised for render phase instead ofuseEffect
's deps, to detect value updates you may want to use an external custom hook for value comparison.
Examples
import React from "react"; import { useForm, useWatch } from "react-hook-form"; function Child({ control }) { const firstName = useWatch({ control, name: "firstName", }); return <p>Watch: {firstName}</p>; } function App() { const { register, control } = useForm({ firstName: "test" }); return ( <form> <input {...register("firstName")} /> <Child control={control} /> </form> ); }
import React from "react"; import { useForm, useWatch } from "react-hook-form"; interface FormInputs { firstName: string; lastName: string; } function FirstNameWatched({ control }: { control: Control<FormInputs> }) { const firstName = useWatch({ control, name: "firstName", // without supply name will watch the entire form, or ['firstName', 'lastName'] to watch both defaultValue: "default" // default value before the render }); return <p>Watch: {firstName}</p>; // only re-render at the custom hook level, when firstName changes } function App() { const { register, control, handleSubmit } = useForm<FormInputs>(); const onSubmit = (data: FormInputs) => { console.log(data) }; return ( <form onSubmit={handleSubmit(onSubmit)}> <label>First Name:</label> <input {...register("firstName")} /> <input {...register("lastName")} /> <input type="submit" /> <FirstNameWatched control={control} /> </form> ); }
useFieldArray:
({ control?: Control, name: string, keyName?: string = 'id' }) => objectVideo
フィールド配列(動的な複数の input)を操作するためのカスタムフック。 このフックの背後にある動機は、より良いユーザーエクスペリエンスとフォームのパフォーマンスを提供することです。この短いビデオで、制御されたフィールド配列と非制御フィールド配列を比較できます。
Name | Type | 必須 | 説明 |
---|---|---|---|
name | string | 関連するフィールド名 | |
control | Object | control オブジェクトは useForm から呼び出されます。 ただし、 FormContext を使用している場合は省略できます。 | |
keyName | string = 'id' | フィールド配列のkey 値、デフォルトは「id」、次のことができます キー名を変更します。 |
このフックは、次のオブジェクト と関数を提供します。
function FieldArray() { const { control, register } = useForm(); const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({ control, // control props comes from useForm (optional: if you are using FormContext) name: "test", // unique name for your Field Array }); return ( {fields.map((field, index) => ( <input key={field.id} // important to include key with field's id {...register(`test.${index}.value`)} /> ))} ); }
重要: useFieldArray
は非制御コンポーネントに基づいて構築されます。 下記の注意事項は、実装時の動作を理解し、注意するのに役立ちます。
useForm
フックでdefaultValues
を指定することにより、fields
配列に値を格納することができます。fields
オブジェクトからid
をコンポーネントのkey
に割り当てていることを確認してください。必ず
defaultValue
をに設定してくださいfields[index]
デフォルト値を設定する場合、 入力で削除またはリセットします。次々とアクションを呼び出すことはできません。アクションはレンダリングごとにトリガーする必要があります 。
// ❌ The following is not correct handleChange={() => { if (fields.length === 2) { remove(0); } append({ test: 'test' }); }} // ✅ The following is correct and second action is triggered after next render handleChange={() => { append({ test: 'test' }); }} React.useEffect(() => { if (fields.length === 2) { remove(0); } }, [fields])
useFieldArray
を使用する際には、ref={register}
ではなくref={register()}
を適用して、map
中にregister
が呼び出されるようにすることが重要です。useEffect
のカスタムレジスタでは機能しません。
Name | Type | 説明 |
---|---|---|
fields | object & { id: string } | このオブジェクトは、input をマップおよびレンダリングするための信頼できる情報源です。 重要: 各 input は制御することができないため、 マップされたコンポーネントには eg: |
append | (obj: object | object[], shouldFocus?: boolean = true) => void | フィールドの最後に input を追加します。 |
prepend | (obj: object | object[], shouldFocus?: boolean = true) => void | フィールドの先頭に input を追加します。 |
insert | (index: number, value: object, shouldFocus?: boolean = true) => void | 特定の位置に input を挿入します。 |
swap | (from: number, to: number) => void | input の位置を入れ替えます。 |
move | (from: number, to: number) => void | input を別の位置に移動します。 注意: |
remove | (index?: number | number[]) => void | 特定の位置の input を削除します。引数で index を渡さない場合は全ての input を削除します。 |
import React from "react"; import { useForm, useFieldArray } from "react-hook-form"; function App() { const { register, control, handleSubmit, reset, trigger, setError } = useForm({ // defaultValues: {}; you can populate the fields by this attribute }); const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({ control, name: "test" }); return ( <form onSubmit={handleSubmit(data => console.log(data))}> <ul> {fields.map((item, index) => ( <li key={item.id}> <input name={`test[${index}].firstName`} ref={register()} defaultValue={item.firstName} // make sure to set up defaultValue /> <Controller as={<input />} name={`test[${index}].lastName`} control={control} defaultValue={item.lastName} // make sure to set up defaultValue /> <button type="button" onClick={() => remove(index)}>Delete</button> </li> ))} </ul> <button type="button" onClick={() => append({ firstName: "appendBill", lastName: "appendLuo" })} > append </button> <input type="submit" /> </form> ); }
高度な使用法
React Hook Form を使用して、複雑でアクセス可能なフォームを構築する方法を学びます。