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><inputid="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
を指定できます。ただし、useForm
に defaultValues
を渡してフォームを初期化するのがより一般的であり、推奨されています。
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: stringlastName: 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>)}
ref にアクセスできない場合はどうすればよいですか?
実際には、ref
なしで入力を register
できます。実際、手動で setValue
、setError
、および 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)}><inputname="firstName"onChange={(e) => setValue("firstName", e.target.value)}/><inputname="lastName"onChange={(e) => {const value = e.target.valueif (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" // V6import { useForm } from "react-hook-form/dist/react-hook-form.ie11" // V5'// Resolversimport { yupResolver } from "@hookform/resolvers/dist/ie11/yup"
React Hook Form、Formik、または Redux Form?
まず、すべてのライブラリは同じ問題を解決しようとしています。つまり、フォームの構築エクスペリエンスをできるだけ簡単にするということです。ただし、これら 3 つの間にはいくつかの根本的な違いがあります。react-hook-form
は非制御入力を念頭に置いて構築されており、フォームに最高のパフォーマンスと可能な限り少ない再レンダリングを提供しようとしています。さらに、react-hook-form
は React Hooks で構築されており、フックとして使用されます。つまり、インポートするコンポーネントはありません。以下に、詳細な違いをいくつか示します
React Hook Form | Formik | Redux 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 |
検証 | 組み込み、Yup、Zod、Joi、Superstruct、および独自に構築します。 | 自分で構築するか、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 (<Controllerrender={({ field }) => <input {...field} />}name="firstName"control={control}defaultValue=""/>)}
ご支援ありがとうございます
プロジェクトで React Hook Form が役立つと思われる場合は、スターを付けてサポートすることを検討してください。