Skip to content

FAQs

よくある質問と答え。

React Hook Formのパフォーマンス

パフォーマンスはこのcustom hookを作成する主な目的の一つでした。 React Hook Formでは非制御コンポーネントによってregister関数をrefで実行しています。 このアプローチにより、ユーザーからの入力や値の変更により発生する再レンダリングの量を削減しています。 コンポーネントのページへのマウントも制御されていないことによりはるかに高速になります。こちらの他のライブラリとのマウントスピードの簡単な比較をご覧下さい。


アクセス可能な入力エラーとメッセージを作成するには?

React Hook Formは非制御コンポーネントに基づいているため、アクセス可能なカスタムフォームを簡単に構築できます。

import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        type="text"
        aria-invalid={errors.firstName ? "true" : "false"}
        name="firstName"
        ref={register({ required: true })}
      />
      { errors.firstName && (
          <span role="alert">
            This field is required
          </span>
        )
      }

      <input type="submit" />
    </form>
  );
}

クラスコンポーネントでも使えますか?

そのままでは動作しませんが、クラスコンポーネントを包むラッパーを作成して使用することは可能です。

クラスコンポーネント内でのHooksの使用は出来ませんが、クラスコンポーネントと Hooksを使用した関数コンポーネントを単一のDOM Tree内で混在させることは可能です。 クラスコンポーネントかHooksを使用した関数コンポーネントのどちらを利用するかは、 そのコンポーネントの実装の詳細に過ぎません。長い目で見れば、 HooksはReactのコンポーネントを書く際の最初の選択肢になっていくだろうと私達は予想しています。

フォームをリセットするには?

フォームをリセットする方法は2つあります。

  • HTMLFormElement.reset()

    フォームのリセットボタンのクリックと同等の効果を持つメソッドです。 フォーム内のinput/select/checkbox要素の値のみリセットします。

  • React Hook Form API: reset()

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


フォームの値を初期化するには?

React Hook Formは非制御コンポーネントによって出来ています。 非制御コンポーネントでは、それぞれのfieldに対してdefaultValueかdefaultCheckedを指定出来ます。 実はこれよりも更に簡単な全てのインプット値の初期化方法をReact Hook Formは提供しています。 下記の例を参考して下さい。

import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm({
    defaultValues: {
      firstName: "bill",
      lastName: "luo",
      email: "bluebill1049@hotmail.com"
    }
  });
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register} />
      <input name="lastName" ref={register} />
      <input name="email" ref={register} />

      <button type="submit">Submit</button>
    </form>
  );
}

refを共有するには?

React Hook Form では入力値を取得するためにrefが必要ですが、refを他の目的(ビューへのスクロールなど)に使用することもできます。下記の例を参考して下さい。

import React, { useRef } from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm();
  const firstNameRef = useRef();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={(e) => {
        register(e)
        firstNameRef.current = e // you can still assign to ref
      }} />
      <input name="lastName" ref={(e) => {
        // register's first argument is ref, and second is validation rules
        register(e, { required: true })
      }} />

      <button>Submit</button>
    </form>
  );
}import React, { useRef } 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>(null);
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={(e) => {
        register(e)
        firstNameRef.current = e // you can still assign to ref
      }} />
      <input name="lastName" ref={(e) => {
        // register's first argument is ref, and second is validation rules
        register(e, { required: true })
      }} />

      <button>Submit</button>
    </form>
  );
}

refへのアクセスが出来ない場合は?

実はrefを使わずともregisterは使用出来ます。 加えてsetValueとsetError、triggerの手動での使用も出来ます。

注: ただしrefが登録されていないため, React Hook Formはinputのイベントリスナーへの登録が出来ず、 そのため値やエラーの更新を手動で行わなければいけません

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({ name: "firstName" }, { required: true });
    register({ name: "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>
  );
}

ブラウザのサポートは?

React Hook Formは全ての主要なブラウザに対応しています。

IE11をサポートしたい場合は、IE11バージョンのreact-hook-formをインポートして下さい。

import { useForm } from 'react-hook-form/dist/index.ie11'; // V6
import { useForm } from 'react-hook-form/dist/react-hook-form.ie11'; // V5'

If you encounter:

Object doesn't support property or method 'find'

You should try to add this find polyfill to the top of your app.js


最初のキーストロークが機能しない場合は?

defaultValueの代わりにvalueを使っていないかよく確認して下さい。

React Hook Formは非制御インプットを基にして作られているため、インプットの値をonChangeでstateを通して変更する必要はありません。valueは使わずに、defaultValueでのインプットの初期値 の設定のみ行って下さい。


MutationObserverが原因でテストに失敗した場合は?

テスト中にMutationObserverが原因の問題が発生した場合は、mutationobserverをインストールしテストのsetup.jsでインポートしてください。

npm i mutationobserver-shim

React Hook Form、FormikそれともRedux Form?

全てのライブラリはフォーム作成の体験を簡単で素晴らしいものにするという同じ問題を解決しようとしていますが 、3つのライブラリーの間にはいくつかの根本的な違いがあります。 react-hook-formは非制御入力を念頭に置いて開発されており、 ベストパフォーマンスのフォームを提供しようとし、再レンダリング数を出来る限り少なく抑えています。 さらに、react-hook-formはReact Hookによって構築され、hookとして使用されます。 つまり、コンポーネントをインポートしません。詳細な違いを以下に示します。

React Hook Form

Formik

Redux Form

Componentuncontrolledcontrolledcontrolled
Rendering最小限の再レンダリングローカル状態の変化に応じて再レンダリングします。つまり、入力時に変化します。状態管理ライブラリ(Redux)の変更に応じて再レンダリングします。 これは、入力時に変化することを意味します。
APIHooksComponent (RenderProps, Form, Field) + HooksComponent (RenderProps, Form, Field)
Package size小
react-hook-form@3.26.2
5.3KB
中
formik@2.0.1
14.4KB
大
redux-form@8.2.6
27KB
ValidationBuilt-in & YupBuild yourself or YupBuild yourself or Plugins
学習曲線低い中中
状況小さなコミュニティ: 新しい成長中のライブラリ大きなコミュニティ: コミュニティによって十分に確立されたフォームライブラリ大きなコミュニティ: コミュニティによって十分に確立されたフォームライブラリ

制御されたコンポーネントと組み合わせて使用することができますか?

短い回答: Yes

React Hook Form は、制御されたフォームを構築することを推奨していませんが、 制御されたコンポーネントと組み合わせて簡単に構築することができます。

それは、watch API を使用して、各入力の変更を監視し、 value prop に割り当てるトリックです。

または、ラッパーコンポーネントの Controller を使用して、これらのカスタム登録を処理できます。

import React from "react";
import { useForm, Controller } from "react-hook-form";
import { TextField } from "@material-ui/core";

function App() {
  const { control, handleSubmit } = useForm();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        as={TextField}
        name="firstName"
        control={control}
        defaultValue=""
      />
      
      <input type="submit" />
    </form>
  );
}
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({ name: "firstName" });
    register({ name: "lastName" });
  }, [register]);

  const handleChange = (name, e) => {
    e.persist();
    setValue(name, e.target.value);
  };

  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        onChange={handleChange.bind(null, "firstName")}
        value={firstName}
      />

      <input onChange={handleChange.bind(null, "lastName")} value={lastName} />
      <input type="submit" />
    </form>
  );
}

React Hook Form のテスト

  • act の警告が表示されるのはなぜですか?

    React Hook Form の全てのバリデーションメソッドは非同期関数として扱われるため、act を async でラップすることが重要です。

  • fireEvent で入力の変更がトリガーされないのはなぜですか?

    React Hook Form は、入力の変更に input イベントを使用しています。 入力の変更がトリガーするために、 react-testing-library の fireEvent.input に簡単に切り替えることができます。


watch vs getValues vs state

  • watch: イベントリスナーを介して input の変更を購読し、購読されているフィールドに基づいて再レンダリングします。 どの input が監視/購読されているかに基づいて再レンダリングします。 実際の動作については、この codesandbox をご覧ください。

  • getValues: カスタムフック内に参照(ref)として格納された値を、高速かつ安価に取得します。 このメソッドは再レンダリングをトリガーしません。

  • local state: React のローカルな状態は input の状態を表すだけでなく、レンダリングするべきかを決定します。 これは、各 input の変更時にトリガーされます。


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

React Hook Form はフォーム全体と全ての input 要素を制御しません。理由は、React が入れ替えられた input 要素を認識しないからです。 解決策として、input 要素に一意な key props を渡すことでこの問題を解決できます。key props について this article written by Kent C. Dodds から詳しく読むことができます。

import React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register } = useForm();

  return (
    <div>
      {watchChecked ? (
        <input ref={register} name="input3" type="text" key="key1" defaultValue="1" />
      ) : (
        <input ref={register} name="input4" type="text" key="key2" defaultValue="2" />
      )}
    </div>
  );
}

Controller は shouldFocusErrorで動作しませんか?

バリデーションエラーのあと、React Hook Form はネイティブの input 要素(例: <input />) または正しく ref が公開されているいくつかのサードパーティコンポーネント(例: MUI の <TextField inputRef={register({required: 'Field Required'})} />)のような適切な ref を持つ無効な要素に自動でフォーカスを当てます。

しかし、いくつかの(MUI の <Autocomplete> や AntD の <XX>のような) サードパーティ制御コンポーネントでは、フォーマットが変更されるため ref を予見することはとても難しいです。 そのため、React Hook Form はバリデーションエラーを正しく見つけますがほとんどのコンポーネントに自動でフォーカスを当てることができません。

回避策として、(もし実際の内部の input 要素の ref を取得できるなら)バリデーションエラーの後に、 手動でサードパーティ制御コンポーネントにフォーカスを当てることができます。例えば:

import React, { useEffect, useRef } from "react"
import { useForm } from "react-hook-form"

export default function App() {
  const inputRef = useRef();
  const { control, handleSubmit, errors } = useForm({});

  useEffect(() => {
    if (errors.test) {
      inputRef.current.focus();
    }
  });

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <Controller as={<ExternalInput ref={inputRef} />} name="test" control={control} rules={{ required: true }} />
      <button>Submit</button>
    </form>
  );
}

もし外部の制御コンポーネントを使って自動でフォーカスを当てることが難しいと感じるなら、 「エラー時の自動フォーカス」機能を無効にすることが可能です。おそらくこの機能は いくつかのケースでより良いユーザー体験をもたらします。useForm({shouldFocusError: false});


モーダルまたはタブ付きのフォームではどのように動作しますか?

React Hook Formがネイティブフォームを受け入れることを理解することが重要です 各入力内に入力状態を保存することによる動作(カスタムを除く)register at useEffect)。一般的な 誤解は、マウントによってモーダルまたはタブフォームを操作するときです 状態を入力するフォーム/入力のアンマウントは残ります。それは 間違った実装ではなく、正しい解決策は常に モーダルまたは各タブ内でフォームの新しいフォームを作成し、 ローカルまたはグローバルな状態で提出データをキャプチャします。

あなたのサポートが必要です

React プロジェクトで React Hook Form が役立つと思う場合は、リポジトリとコントリビューターをサポートするためにスターを付けてください ❤

Edit