コンテンツへスキップ

useForm

フォームバリデーションのためのReactフック

</> useForm: UseFormProps

useFormは、フォームを簡単に管理するためのカスタムフックです。オプションの引数として1つのオブジェクトを取ります。次の例では、すべてのプロパティとそのデフォルト値を示します。

汎用プロパティ

オプション説明
mode送信する**前**のバリデーション戦略。
reValidateMode送信する**後**のバリデーション戦略。
defaultValuesフォームのデフォルト値。
valuesフォームの値を更新するためのリアクティブな値。
errorsフォームのエラーを更新するためのリアクティブなエラー。
resetOptions新しいフォーム値を更新する際のフォーム状態更新をリセットするためのオプション。
criteriaModeすべてのバリデーションエラーを表示するか、一度に1つずつ表示するか。
shouldFocusErrorビルトインのフォーカス管理を有効または無効にする。
delayErrorエラーの表示を遅らせる。
shouldUseNativeValidationブラウザのビルトインフォーム制約APIを使用する。
shouldUnregisterアンマウント後の入力の登録解除を有効または無効にする。
disabled関連するすべての入力と共に、フォーム全体を無効にする。

スキーマバリデーションプロパティ

オプション説明
resolver好みのスキーマバリデーションライブラリと統合する。
contextスキーマバリデーションに提供するコンテキストオブジェクト。

プロパティ


mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit' React Native: Controllerと互換性あり


このオプションを使用すると、ユーザーがフォームを送信する前にバリデーション戦略を設定できます。バリデーションは、handleSubmit関数を呼び出すことでトリガーされるonSubmitイベント中に発生します。

名前説明
onSubmit文字列バリデーションはsubmitイベントでトリガーされ、入力はonChangeイベントリスナーをアタッチして自身を再検証します。
onBlur文字列バリデーションはblurイベントでトリガーされます。
onChange文字列各入力のchangeイベントでバリデーションがトリガーされ、複数回の再レンダリングにつながります。警告:これは多くの場合、パフォーマンスに大きな影響を与えます。
onTouched文字列バリデーションは最初にblurイベントでトリガーされます。その後、すべてのchangeイベントでトリガーされます。

注記:Controllerと共に使用する場合、onBlurrenderプロップに接続してください。
all文字列バリデーションはblurイベントとchangeイベントの両方でトリガーされます。

reValidateMode: onChange | onBlur | onSubmit = 'onChange' React Native: カスタム登録またはControllerの使用


このオプションを使用すると、ユーザーがフォームを送信した後に(onSubmitイベントとhandleSubmit関数が実行された後)、エラーのある入力が再検証される際のバリデーション戦略を設定できます。デフォルトでは、再検証は入力変更イベント中に発生します。

defaultValues: FieldValues | () => Promise<FieldValues>


defaultValuesプロップは、フォーム全体をデフォルト値で設定します。同期および非同期のデフォルト値の割り当てをサポートしています。defaultValueまたはdefaultCheckedを使用して入力のデフォルト値を設定できます(公式Reactドキュメントに記載されているとおり)が、フォーム全体にはdefaultValuesを使用することを推奨します。

useForm({
defaultValues: {
firstName: '',
lastName: ''
}
})
// set default value async
useForm({
defaultValues: async () => fetch('/api-endpoint');
})
ルール
  • 制御されたコンポーネントのデフォルト状態と競合するため、undefinedをデフォルト値として指定することは避ける必要があります。

  • defaultValuesはキャッシュされます。リセットするには、resetAPIを使用します。

  • defaultValuesはデフォルトで送信結果に含まれます。

  • MomentLuxonなど、プロトタイプメソッドを含むカスタムオブジェクトをdefaultValuesとして使用することは避けることをお勧めします。

  • フォームデータを含めるための他のオプションがあります。

    <input {...register("hidden", { value: "data" })} type="hidden" />
    // include data onSubmit
    const onSubmit = (data) => {
    const output = {
    ...data,
    others: "others",
    }
    }

values: FieldValues


valuesプロップは変更に反応してフォームの値を更新します。これは、フォームを外部の状態またはサーバーデータによって更新する必要がある場合に役立ちます。valuesプロップは、resetOptions: { keepDefaultValues: true }useFormにも設定されていない限り、defaultValuesプロップを上書きします。

// set default value sync
function App({ values }) {
useForm({
values, // will get updated when values props updates
})
}
function App() {
const values = useFetch("/api")
useForm({
defaultValues: {
firstName: "",
lastName: "",
},
values, // will get updated once values returns
})
}

errors: FieldErrors


errorsプロップは変更に反応してサーバーエラーの状態を更新します。これは、フォームを外部のサーバーが返したエラーによって更新する必要がある場合に役立ちます。

function App() {
const { errors, data } = useFetch("/api")
useForm({
errors, // will get updated once errors returns
})
}

resetOptions: KeepStateOptions


このプロパティは、値の更新動作に関連しています。valuesまたはdefaultValuesが更新されると、内部的にresetAPIが呼び出されます。valuesまたはdefaultValuesが非同期で更新された後の目的の動作を指定することが重要です。設定オプション自体は、resetメソッドのオプションへの参照です。

// by default asynchronously value or defaultValues update will reset the form values
useForm({ values })
useForm({ defaultValues: async () => await fetch() })
// options to config the behaviour
// eg: I want to keep user interacted/dirty value and not remove any user errors
useForm({
values,
resetOptions: {
keepDirtyValues: true, // user-interacted input will be retained
keepErrors: true, // input errors will be retained with value update
},
})

context: object


このコンテキストobjectは変更可能であり、resolverの第2引数またはYupバリデーションのコンテキストオブジェクトに挿入されます。 CodeSandbox

criteriaMode: firstError | all


  • firstError(デフォルト)に設定されている場合、各フィールドから最初のエラーのみが収集されます。
  • allに設定されている場合、各フィールドからすべてのエラーが収集されます。
CodeSandbox

shouldFocusError: boolean = true


true(デフォルト)に設定されている場合、ユーザーがバリデーションに失敗したフォームを送信すると、エラーのある最初のフィールドにフォーカスが設定されます。

注記
  • refを持つ登録済みフィールドのみが機能します。カスタム登録された入力は適用されません。例:register('test') // 機能しません
  • フォーカスの順序は、registerの順序に基づいています。

delayError: number


この設定は、エラー状態のエンドユーザーへの表示を、指定したミリ秒数遅らせます。ユーザーがエラー入力を修正した場合、エラーは即座に削除され、遅延は適用されません。 CodeSandbox

shouldUnregister: boolean = false


デフォルトでは、入力が削除されても入力値は保持されます。ただし、shouldUnregistertrue に設定して、アンマウント時に入力の登録解除を行うことができます。

  • これはグローバル設定であり、子レベルの設定を上書きします。個々の動作を持たせるには、useFormではなく、コンポーネントまたはフックレベルで設定してください。

  • デフォルトでは、shouldUnregister: false は、アンマウントされたフィールドが組み込みの検証によって検証されないことを意味します。

  • useFormレベルでshouldUnregisterをtrueに設定すると、defaultValuesは送信結果とマージされません

  • shouldUnregister: true を設定すると、フォームの動作がネイティブフォームにより近くなります。

    • フォームの値は、入力自体に格納されます。

    • 入力のアンマウントは、その値を削除します。

    • 非表示の入力には、非表示のデータの保存にhidden属性を使用する必要があります。

    • 登録された入力のみが送信データに含まれます。

    • アンマウントされた入力は、フックフォームがDOMから入力がアンマウントされていることを確認するために、useFormまたはuseWatchuseEffectで通知する必要があります。

      const NotWork = () => {
      const [show, setShow] = React.useState(false)
      // ❌ won't get notified, need to invoke unregister
      return show && <input {...register("test")} />
      }
      const Work = ({ control }) => {
      const { show } = useWatch({ control })
      // ✅ get notified at useEffect
      return show && <input {...register("test1")} />
      }
      const App = () => {
      const [show, setShow] = React.useState(false)
      const { control } = useForm({ shouldUnregister: true })
      return (
      <div>
      // ✅ get notified at useForm's useEffect
      {show && <input {...register("test2")} />}
      <NotWork />
      <Work control={control} />
      </div>
      )
      }

shouldUseNativeValidation: boolean = false


この設定により、ブラウザのネイティブ検証が有効になります。また、CSSセレクター:valid:invalidが有効になり、入力のスタイル設定が容易になります。クライアント側の検証が無効になっている場合でも、これらのセレクターを使用できます。

  • reportValidityの実行によってエラー入力にフォーカスが設定されるため、onSubmitモードとonChangeモードでのみ機能します。
  • ネイティブに表示するには、登録された各フィールドの検証メッセージは文字列である必要があります。
  • この機能は、実際のDOM参照に接続されているregister APIとuseController/Controllerでのみ機能します。


import { useForm } from "react-hook-form"
export default function App() {
const { register, handleSubmit } = useForm({
shouldUseNativeValidation: true,
})
const onSubmit = async (data) => {
console.log(data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("firstName", {
required: "Please enter your first name.",
})} // custom message
/>
<input type="submit" />
</form>
)
}

disabled: boolean = false


この設定を使用すると、trueに設定した場合、フォーム全体と関連するすべての入力を無効にすることができます。
これは、非同期タスク中または入力が一時的に応答しない必要があるその他の状況で、ユーザーの操作を防止するのに役立ちます。


import { useForm, Controller } from "react-hook-form"
const App = () => {
const [disabled, setDisabled] = useState(false)
const { register, handleSubmit, control } = useForm({
disabled,
})
return (
<form
onSubmit={handleSubmit(async () => {
setDisabled(true)
await sleep(100)
setDisabled(false)
})}
>
<input
type={"checkbox"}
{...register("checkbox")}
data-testid={"checkbox"}
/>
<select {...register("select")} data-testid={"select"} />
<Controller
control={control}
render={({ field }) => <input disabled={field.disabled} />}
name="test"
/>
<button type="submit">Submit</button>
</form>
)
}

resolver: Resolver


この関数を使用すると、YupZodJoiVestAjvなど、任意の外部検証ライブラリを使用できます。目標は、好みの検証ライブラリをシームレスに統合できるようにすることです。ライブラリを使用していない場合は、独自のロジックを記述してフォームを検証することもできます。

npm install @hookform/resolvers
プロパティ

名前説明
valuesオブジェクトこのオブジェクトには、フォームの値全体が含まれています。
contextオブジェクトこれは、useFormの設定に提供できるcontextオブジェクトです。これは、各再レンダリング時に変更できる変更可能なオブジェクトです。
オプション
{
  "criteriaMode": "string",
  "fields": "object",
  "names": "string[]"
}
これは、検証されたフィールド、名前、およびuseFormからのcriteriaModeに関する情報を含むオプションオブジェクトです。
ルール
  • スキーマ検証は、フィールドレベルのエラーレポートに焦点を当てています。親レベルのエラーチェックは直接の親レベルに限定され、グループチェックボックスなどのコンポーネントに適用されます。
  • この関数はキャッシュされます。
  • 入力の再検証は、ユーザーの操作中は一度に1つのフィールドのみ発生します。ライブラリ自体は、errorオブジェクトを評価して、それに応じて再レンダリングをトリガーします。
  • リゾルバーは、組み込みのバリデーター(例:required、minなど)と併用することはできません。
  • カスタムリゾルバーを作成する場合
    • valuesプロパティとerrorsプロパティの両方を持つオブジェクトを返すようにしてください。それらのデフォルト値は空のオブジェクトにする必要があります。例:{}
    • errorオブジェクトのキーは、フィールドのname値と一致する必要があります。


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>
)
}
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
const schema = z.object({
name: z.string(),
age: z.number(),
})
type Schema = z.infer<typeof schema>
const App = () => {
const { register, handleSubmit } = useForm<Schema>({
resolver: zodResolver(schema),
})
const onSubmit = (data: Schema) => {
console.log(data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} />
<input {...register("age", { valueAsNumber: true })} type="number" />
<input type="submit" />
</form>
)
}
import React from "react";
import { useForm } from "react-hook-form";
import { joiResolver } from "@hookform/resolvers/joi";
import Joi from "joi";
interface IFormInput {
name: string;
age: number;
}
const schema = Joi.object({
name: Joi.string().required(),
age: Joi.number().required()
});
const App = () => {
const { register, handleSubmit, formState: { errors } } = useForm<IFormInput>({
resolver: joiResolver(schema)
});
const onSubmit = (data: IFormInput) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name"} />
<input type="number" {...register("age"} />
<input type="submit" />
</form>
);
}
import { useForm } from "react-hook-form"
import { ajvResolver } from "@hookform/resolvers/ajv"
// must use `minLength: 1` to implement required field
const schema = {
type: "object",
properties: {
username: {
type: "string",
minLength: 1,
errorMessage: { minLength: "username field is required" },
},
password: {
type: "string",
minLength: 1,
errorMessage: { minLength: "password field is required" },
},
},
required: ["username", "password"],
additionalProperties: false,
}
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: ajvResolver(schema),
})
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register("username")} />
{errors.username && <p>{errors.username.message}</p>}
<input {...register("password")} />
{errors.password && <p>{errors.password.message}</p>}
<button type="submit">submit</button>
</form>
)
}
import * as React from "react"
import { useForm } from "react-hook-form"
import { vestResolver } from "@hookform/resolvers/vest"
import vest, { test, enforce } from "vest"
const validationSuite = vest.create((data = {}) => {
test("username", "Username is required", () => {
enforce(data.username).isNotEmpty()
})
test("username", "Must be longer than 3 chars", () => {
enforce(data.username).longerThan(3)
})
test("password", "Password is required", () => {
enforce(data.password).isNotEmpty()
})
test("password", "Password must be at least 5 chars", () => {
enforce(data.password).longerThanOrEquals(5)
})
test("password", "Password must contain a digit", () => {
enforce(data.password).matches(/[0-9]/)
})
test("password", "Password must contain a symbol", () => {
enforce(data.password).matches(/[^A-Za-z0-9]/)
})
})
const App = () => {
const { register, handleSubmit } = useForm({
resolver: vestResolver(validationSuite),
})
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register("username")} />
<input {...register("password")} />
<input type="submit" />
</form>
)
}
import * as React from "react"
import { useForm } from "react-hook-form"
import * as Joi from "joi"
interface IFormInputs {
username: string
}
const validationSchema = Joi.object({
username: Joi.string().alphanum().min(3).max(30).required(),
})
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<IFormInputs>({
resolver: async (data) => {
const { error, value: values } = validationSchema.validate(data, {
abortEarly: false,
})
return {
values: error ? {} : values,
errors: error
? error.details.reduce((previous, currentError) => {
return {
...previous,
[currentError.path[0]]: currentError,
}
}, {})
: {},
}
},
})
const onSubmit = (data: IFormInputs) => console.log(data)
return (
<div className="App">
<h1>resolver</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<label>Username</label>
<input {...register("username")} />
{errors.username && <p>errors.username.message</p>}
<input type="submit" />
</form>
</div>
)
}

詳細については、Resolver Documentationを参照してください。

ヒント

次のコードスニペットを使用して、スキーマをデバッグできます。

resolver: async (data, context, options) => {
// you can debug your validation schema here
console.log("formData", data)
console.log(
"validation result",
await anyResolver(schema)(data, context, options)
)
return anyResolver(schema)(data, context, options)
}

戻り値


次のリストには、useFormの戻り値のプロパティへの参照が含まれています。

ご支援ありがとうございます。

React Hook Formがプロジェクトで役立つと感じた場合は、スターを付けてサポートをご検討ください。