コンテンツへスキップ

よくある質問 (FAQ)

よくある質問

React Hook Form のパフォーマンス

パフォーマンスは、このライブラリが作成された主な理由の 1 つです。 React Hook Form は、非制御フォームに依存しています。これが、register 関数が ref をキャプチャし、制御されたコンポーネントが Controller または useController で再レンダリングされる理由です。このアプローチにより、ユーザーが入力欄に入力したり、フォームまたはアプリケーションのルートで他のフォームの値が変更されたりすることによって発生する再レンダリングの量が削減されます。コンポーネントはオーバーヘッドが少ないため、制御されたコンポーネントよりもページへのマウントが高速です。参考までに、このリポジトリリンクで参照できるクイック比較テストがあります。


アクセシブルな入力エラーとメッセージを作成する方法

React Hook Form は非制御コンポーネントに基づいているため、アクセシブルなカスタムフォームを簡単に構築できます。(非制御コンポーネントの詳細については、「コンポーネント間で状態を共有する」を参照してください。)

import React from "react"
import { useForm } from "react-hook-form"
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm()
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="firstName">First name</label>
<input
id="firstName"
aria-invalid={errors.firstName ? "true" : "false"}
{...register("firstName", { required: true })}
/>
{errors.firstName && <span role="alert">This field is required</span>}
<input type="submit" />
</form>
)
}

クラスコンポーネントで動作しますか?

いいえ、そのままでは動作しません。これを行う場合は、ラッパーを構築してクラスコンポーネントで使用できます。

クラスコンポーネント内でフックを使用することはできませんが、クラスとフックを使用する関数コンポーネントを単一のツリーに混在させることは間違いなく可能です。コンポーネントがクラスであるか、フックを使用する関数であるかは、単にそのコンポーネントの実装の詳細です。長期的には、フックが人々が React コンポーネントを作成する主な方法になると予想されます。


フォームをリセットする方法

フォームをクリアする方法は 2 つあります

  • HTMLFormElement.reset()

    このメソッドは、フォームのリセットボタンをクリックするのと同じことを行います。input/select/checkbox の値のみをクリアします。

  • React Hook Form API: reset()

    React Hook Form の reset メソッドは、すべてのフィールド値をリセットし、フォーム内のすべての errors もクリアします。


フォームの値を初期化する方法

React Hook Form は非制御フォームに依存しているため、個々のフィールドに defaultValue または defaultChecked を指定できます。ただし、useFormdefaultValues を渡してフォームを初期化するのがより一般的であり、推奨されています。

function App() {
const { register, handleSubmit } = useForm({
defaultValues: {
firstName: "bill",
lastName: "luo",
},
})
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<button type="submit">Submit</button>
</form>
)
}

非同期のデフォルト値については、次のメソッドを使用できます

  • 非同期 defaultValues

    function App() {
    const { register, handleSubmit } = useForm({
    defaultValues: async () => {
    const response = await fetch("/api")
    return await response.json() // return { firstName: '', lastName: '' }
    },
    })
    }
  • リアクティブ values

    function App() {
    const { data } = useQuery() // data returns { firstName: '', lastName: '' }
    const { register, handleSubmit } = useForm({
    values: data,
    resetOptions: {
    keepDirtyValues: true, // keep dirty fields unchanged, but update defaultValues
    },
    })
    }

ref の使い方を共有する方法

React Hook Form は、入力値を取得するために ref を必要とします。ただし、他の目的 (ビューへのスクロールやフォーカスなど) で ref を使用することもできます。

import { useRef, useImperativeHandle } from "react"
import { useForm } from "react-hook-form"
type Inputs = {
firstName: string
lastName: string
}
export default function App() {
const { register, handleSubmit } = useForm<Inputs>()
const firstNameRef = useRef<HTMLInputElement>(null)
const onSubmit = (data: Inputs) => console.log(data)
const { ref, ...rest } = register("firstName")
const onClick = () => {
firstNameRef.current!.value = ""
}
useImperativeHandle(ref, () => firstNameRef.current)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...rest} ref={firstNameRef} />
<button type="button" onClick={onClick}>
clear
</button>
<button>Submit</button>
</form>
)
}
import { useRef, useImperativeHandle } from "react"
import { useForm } from "react-hook-form"
export default function App() {
const { register, handleSubmit } = useForm()
const firstNameRef = useRef(null)
const onSubmit = (data) => console.log(data)
const { ref, ...rest } = register("firstName")
const onClick = () => {
firstNameRef.current!.value = ""
}
useImperativeHandle(ref, () => firstNameRef.current)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...rest} ref={firstNameRef} />
<button type="button" onClick={onClick}>
clear
</button>
<button>Submit</button>
</form>
)
}

ref にアクセスできない場合はどうすればよいですか?

実際には、ref なしで入力を register できます。実際、手動で setValuesetError、および trigger を行うことができます。

注: ref が登録されていないため、React Hook Form は入力へのイベントリスナーの登録を完了できません。つまり、値とエラーを手動で更新する必要があります。

import React, { useEffect } from "react"
import { useForm } from "react-hook-form"
export default function App() {
const { register, handleSubmit, setValue, setError } = useForm()
const onSubmit = (data) => console.log(data)
useEffect(() => {
register("firstName", { required: true })
register("lastName")
}, [])
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
name="firstName"
onChange={(e) => setValue("firstName", e.target.value)}
/>
<input
name="lastName"
onChange={(e) => {
const value = e.target.value
if (value === "test") {
setError("lastName", "notMatch")
} else {
setValue("lastName", e.target.value)
}
}}
/>
<button>Submit</button>
</form>
)
}

最初のキーストロークが機能しないのはなぜですか?

value を使用していないことを確認してください。正しいプロパティは defaultValue です。

React Hook Form は非制御入力に焦点を当てているため、onChange を介して state を介して入力 value を変更する必要はありません。実際、value はまったく必要ありません。初期入力値には defaultValue を設定するだけで済みます。

import { useForm } from "react-hook-form/dist/index.ie11" // V6
import { useForm } from "react-hook-form/dist/react-hook-form.ie11" // V5'
// Resolvers
import { yupResolver } from "@hookform/resolvers/dist/ie11/yup"

React Hook Form、Formik、または Redux Form?

まず、すべてのライブラリは同じ問題を解決しようとしています。つまり、フォームの構築エクスペリエンスをできるだけ簡単にするということです。ただし、これら 3 つの間にはいくつかの根本的な違いがあります。react-hook-form は非制御入力を念頭に置いて構築されており、フォームに最高のパフォーマンスと可能な限り少ない再レンダリングを提供しようとしています。さらに、react-hook-form は React Hooks で構築されており、フックとして使用されます。つまり、インポートするコンポーネントはありません。以下に、詳細な違いをいくつか示します

React Hook FormFormikRedux Form
コンポーネント非制御 & 制御制御制御
レンダリング最小限の再レンダリングと計算の最適化ローカル状態の変更に応じて再レンダリング (入力時に)。状態管理ライブラリ (Redux) の変更に応じて再レンダリング (入力時に)。
APIフックコンポーネント (RenderProps、Form、Field) + フックコンポーネント (RenderProps、Form、Field)
パッケージサイズ
react-hook-form@7.27.0
8.5KB

formik@2.1.4
15KB

redux-form@8.3.6
26.4KB
検証組み込み、YupZodJoiSuperstruct、および独自に構築します。自分で構築するか、Yup自分で構築するか、プラグイン
学習曲線低~中

watch vs getValues vs state

  • watch: すべての入力または指定された入力の変更をイベントリスナー経由でサブスクライブし、サブスクライブされているフィールドに基づいて再レンダリングします。実際の動作については、この codesandbox を確認してください。
  • getValues: カスタムフック内に参照として格納されている値を取得します。高速で安価です。このメソッドは再レンダリングをトリガーしません。
  • ローカル状態: React ローカル状態は単なる入力の状態以上のものであり、レンダリングするものを決定します。これは、入力が変更されるたびにトリガーされます。

三項演算子でデフォルト値が正しく変更されないのはなぜですか?

React Hook Form はフォームと入力を完全に制御するわけではないため、React は実際の入力が交換またはスワップされたことを認識しません。解決策として、入力に一意の key プロップを与えることでこの問題を解決できます。キープロップの詳細については、ケント・C・ドッズによるこの記事を参照してください。

import React from "react"
import { useForm } from "react-hook-form"
export default function App() {
const { register } = useForm()
return (
<div>
{watchChecked ? (
<input {...register("input3")} key="key1" defaultValue="1" />
) : (
<input {...register("input4")} key="key2" defaultValue="2" />
)}
</div>
)
}

モーダルフォームまたはタブフォームを扱う方法

React Hook Form は、各入力内に入力状態を格納することによって、ネイティブのフォーム動作を受け入れることを理解することが重要です (useEffect でのカスタム register を除く)。よくある誤解は、入力状態がマウントまたはアンマウントされた入力に残っているということです。モーダルフォームやタブフォームを扱う場合などです。代わりに、正しい解決策は、各モーダルまたはタブ内でフォームの新しいフォームを構築し、ローカルまたはグローバル状態に送信データをキャプチャしてから、結合されたデータを使用して何かを行うことです。

あるいは、useForm を呼び出すときに、非推奨のオプション shouldUnregister: false を使用することもできます。

import { useForm, Controller } from "react-hook-form"
function App() {
const { control } = useForm()
return (
<Controller
render={({ field }) => <input {...field} />}
name="firstName"
control={control}
defaultValue=""
/>
)
}
import React, { useEffect } from "react"
import { useForm } from "react-hook-form"
function App() {
const { register, watch, setValue, handleSubmit } = useForm({
defaultValues: {
firstName: "",
lastName: "",
},
})
const { firstName, lastName } = watch()
useEffect(() => {
register("firstName")
register("lastName")
}, [register])
const handleChange = (e, name) => {
setValue(name, e.target.value)
}
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input onChange={(e) => handleChange(e, "firstName")} value={firstName} />
<input onChange={(e) => handleChange(e, "lastName")} value={lastName} />
<input type="submit" />
</form>
)
}

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

プロジェクトで React Hook Form が役立つと思われる場合は、スターを付けてサポートすることを検討してください。