インストール
React Hook Formのインストールは、1つのコマンドを実行するだけで完了します。
npm install react-hook-form
例
以下のコードは、基本的な使用例を示しています。
import { useForm, SubmitHandler } from "react-hook-form"type Inputs = {example: stringexampleRequired: string}export default function App() {const {register,handleSubmit,watch,formState: { errors },} = useForm<Inputs>()const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)console.log(watch("example")) // watch input value by passing the name of itreturn (/* "handleSubmit" will validate your inputs before invoking "onSubmit" */<form onSubmit={handleSubmit(onSubmit)}>{/* register your input into the hook by invoking the "register" function */}<input defaultValue="test" {...register("example")} />{/* include validation with required or other standard HTML validation rules */}<input {...register("exampleRequired", { required: true })} />{/* errors will return when field validation fails */}{errors.exampleRequired && <span>This field is required</span>}<input type="submit" /></form>)}
React Web ビデオチュートリアル
このビデオチュートリアルでは、React Hook Formの基本的な使用方法と概念を説明します。
フィールドの登録
React Hook Formの重要な概念の1つは、コンポーネントをフックに **登録
** することです。 これにより、フォームのバリデーションと送信の両方で値を使用できるようになります。
**注:** 登録プロセスでは、各フィールドにキーとして `name` が **必須** です。
import ReactDOM from "react-dom"import { useForm, SubmitHandler } from "react-hook-form"enum GenderEnum {female = "female",male = "male",other = "other",}interface IFormInput {firstName: stringgender: GenderEnum}export default function App() {const { register, handleSubmit } = useForm<IFormInput>()const onSubmit: SubmitHandler<IFormInput> = (data) => console.log(data)return (<form onSubmit={handleSubmit(onSubmit)}><label>First Name</label><input {...register("firstName")} /><label>Gender Selection</label><select {...register("gender")}><option value="female">female</option><option value="male">male</option><option value="other">other</option></select><input type="submit" /></form>)}
バリデーションの適用
React Hook Formは、既存のHTML標準のフォームバリデーションに準拠することで、フォームバリデーションを容易にします。
サポートされているバリデーションルールのリスト
- 必須
- 最小値
- 最大値
- 最小文字数
- 最大文字数
- パターン
- カスタムバリデーション
各ルールの詳細は、登録セクションをご覧ください。
import { useForm, SubmitHandler } from "react-hook-form"interface IFormInput {firstName: stringlastName: stringage: number}export default function App() {const { register, handleSubmit } = useForm<IFormInput>()const onSubmit: SubmitHandler<IFormInput> = (data) => console.log(data)return (<form onSubmit={handleSubmit(onSubmit)}><input {...register("firstName", { required: true, maxLength: 20 })} /><input {...register("lastName", { pattern: /^[A-Za-z]+$/i })} /><input type="number" {...register("age", { min: 18, max: 99 })} /><input type="submit" /></form>)}
既存のフォームの統合
既存のフォームの統合は簡単です。 重要な手順は、コンポーネントの `ref` を `登録` し、関連するプロパティを入力に割り当てることです。
import { Path, useForm, UseFormRegister, SubmitHandler } from "react-hook-form"interface IFormValues {"First Name": stringAge: number}type InputProps = {label: Path<IFormValues>register: UseFormRegister<IFormValues>required: boolean}// The following component is an example of your existing Input Componentconst Input = ({ label, register, required }: InputProps) => (<><label>{label}</label><input {...register(label, { required })} /></>)// you can use React.forwardRef to pass the ref tooconst Select = React.forwardRef<HTMLSelectElement,{ label: string } & ReturnType<UseFormRegister<IFormValues>>>(({ onChange, onBlur, name, label }, ref) => (<><label>{label}</label><select name={name} ref={ref} onChange={onChange} onBlur={onBlur}><option value="20">20</option><option value="30">30</option></select></>))const App = () => {const { register, handleSubmit } = useForm<IFormValues>()const onSubmit: SubmitHandler<IFormValues> = (data) => {alert(JSON.stringify(data))}return (<form onSubmit={handleSubmit(onSubmit)}><Input label="First Name" register={register} required /><Select label="Age" {...register("Age")} /><input type="submit" /></form>)}
UIライブラリとの統合
React Hook Formは、外部UIコンポーネントライブラリとの統合を容易にしています。 コンポーネントが入力の `ref` を公開していない場合は、Controllerコンポーネントを使用する必要があります。このコンポーネントは登録プロセスを処理します。
import Select from "react-select"import { useForm, Controller, SubmitHandler } from "react-hook-form"import { Input } from "@material-ui/core"interface IFormInput {firstName: stringlastName: stringiceCreamType: { label: string; value: string }}const App = () => {const { control, handleSubmit } = useForm({defaultValues: {firstName: "",lastName: "",iceCreamType: {},},})const onSubmit: SubmitHandler<IFormInput> = (data) => {console.log(data)}return (<form onSubmit={handleSubmit(onSubmit)}><Controllername="firstName"control={control}render={({ field }) => <Input {...field} />}/><Controllername="iceCreamType"control={control}render={({ field }) => (<Select{...field}options={[{ value: "chocolate", label: "Chocolate" },{ value: "strawberry", label: "Strawberry" },{ value: "vanilla", label: "Vanilla" },]}/>)}/><input type="submit" /></form>)}
制御された入力の統合
このライブラリは、制御されていないコンポーネントとネイティブHTML入力を採用しています。 ただし、React-Select、AntD、MUIなどの外部の制御されたコンポーネントを扱うことは避けられません。 これを簡単にするために、ラッパーコンポーネントであるControllerを提供し、統合プロセスを合理化すると同時に、カスタム登録を使用する自由を提供します。
コンポーネントAPIの使用
import { useForm, Controller, SubmitHandler } from "react-hook-form"import { TextField, Checkbox } from "@material-ui/core"interface IFormInputs {TextField: stringMyCheckbox: boolean}function App() {const { handleSubmit, control, reset } = useForm<IFormInputs>({defaultValues: {MyCheckbox: false,},})const onSubmit: SubmitHandler<IFormInputs> = (data) => console.log(data)return (<form onSubmit={handleSubmit(onSubmit)}><Controllername="MyCheckbox"control={control}rules={{ required: true }}render={({ field }) => <Checkbox {...field} />}/><input type="submit" /></form>)}
Hooks APIの使用
import * as React from "react"import { useForm, useController, UseControllerProps } from "react-hook-form"type FormValues = {FirstName: string}function Input(props: UseControllerProps<FormValues>) {const { field, fieldState } = useController(props)return (<div><input {...field} placeholder={props.name} /><p>{fieldState.isTouched && "Touched"}</p><p>{fieldState.isDirty && "Dirty"}</p><p>{fieldState.invalid ? "invalid" : "valid"}</p></div>)}export default function App() {const { handleSubmit, control } = useForm<FormValues>({defaultValues: {FirstName: "",},mode: "onChange",})const onSubmit = (data: FormValues) => console.log(data)return (<form onSubmit={handleSubmit(onSubmit)}><Input control={control} name="FirstName" rules={{ required: true }} /><input type="submit" /></form>)}
グローバル状態との統合
このライブラリは状態管理ライブラリに依存する必要はありませんが、簡単に統合できます。
import { useForm } from "react-hook-form"import { connect } from "react-redux"import updateAction from "./actions"export default function App(props) {const { register, handleSubmit, setValue } = useForm({defaultValues: {firstName: "",lastName: "",},})// Submit your data into Redux storeconst onSubmit = (data) => props.updateAction(data)return (<form onSubmit={handleSubmit(onSubmit)}><input {...register("firstName")} /><input {...register("lastName")} /><input type="submit" /></form>)}// Connect your component with reduxconnect(({ firstName, lastName }) => ({ firstName, lastName }),updateAction)(YourForm)
エラー処理
React Hook Formは、フォームのエラーを表示するための `errors` オブジェクトを提供します。 `errors` のタイプは、指定されたバリデーション制約を返します。 次の例は、必須のバリデーションルールを示しています。
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("firstName", { required: true })}aria-invalid={errors.firstName ? "true" : "false"}/>{errors.firstName?.type === "required" && (<p role="alert">First name is required</p>)}<input{...register("mail", { required: "Email Address is required" })}aria-invalid={errors.mail ? "true" : "false"}/>{errors.mail && <p role="alert">{errors.mail.message}</p>}<input type="submit" /></form>)}
サービスとの統合
React Hook Formをサービスと統合するには、ライブラリに組み込まれている送信処理を使用できます。 `<Form />`コンポーネントを使用すると、フォームデータをAPIエンドポイントまたは他のサービスに簡単に送信できます。 Formコンポーネントの詳細はこちら。
import { Form } from "react-hook-form"function App() {const { register, control } = useForm()return (<Formaction="/api/save" // Send post request with the FormData// encType={'application/json'} you can also switch to json objectonSuccess={() => {alert("Your application is updated.")}}onError={() => {alert("Submission has failed.")}}control={control}><input {...register("firstName", { required: true })} /><input {...register("lastName", { required: true })} /><button>Submit</button></Form>)}
スキーマバリデーション
Yup、Zod、Superstruct、Joiを使用したスキーマベースのフォームバリデーションもサポートしています。`schema` をオプション設定としてuseFormに渡すことができます。 入力データがスキーマに対して検証され、エラーまたは有効な結果が返されます。
**ステップ1:** プロジェクトに `Yup` をインストールします。
npm install @hookform/resolvers yup
**ステップ2:** バリデーションのスキーマを準備し、React Hook Formで入力を登録します。
import { useForm } from "react-hook-form"import { yupResolver } from "@hookform/resolvers/yup"import * as yup from "yup"const schema = yup.object({firstName: yup.string().required(),age: yup.number().positive().integer().required(),}).required()export default function App() {const {register,handleSubmit,formState: { errors },} = useForm({resolver: yupResolver(schema),})const onSubmit = (data) => console.log(data)return (<form onSubmit={handleSubmit(onSubmit)}><input {...register("firstName")} /><p>{errors.firstName?.message}</p><input {...register("age")} /><p>{errors.age?.message}</p><input type="submit" /></form>)}
React Native
React Nativeでも同じパフォーマンスの向上と強化が得られます。 入力コンポーネントと統合するには、`Controller` でラップします。
import { Text, View, TextInput, Button, Alert } from "react-native"import { useForm, Controller } from "react-hook-form"export default function App() {const {control,handleSubmit,formState: { errors },} = useForm({defaultValues: {firstName: "",lastName: "",},})const onSubmit = (data) => console.log(data)return (<View><Controllercontrol={control}rules={{required: true,}}render={({ field: { onChange, onBlur, value } }) => (<TextInputplaceholder="First name"onBlur={onBlur}onChangeText={onChange}value={value}/>)}name="firstName"/>{errors.firstName && <Text>This is required.</Text>}<Controllercontrol={control}rules={{maxLength: 100,}}render={({ field: { onChange, onBlur, value } }) => (<TextInputplaceholder="Last name"onBlur={onBlur}onChangeText={onChange}value={value}/>)}name="lastName"/><Button title="Submit" onPress={handleSubmit(onSubmit)} /></View>)}
TypeScript
React Hook Formは `TypeScript` で構築されており、フォーム値をサポートするために `FormData` タイプを定義できます。
import * as React from "react"import { useForm } from "react-hook-form"type FormData = {firstName: stringlastName: string}export default function App() {const {register,setValue,handleSubmit,formState: { errors },} = useForm<FormData>()const onSubmit = handleSubmit((data) => console.log(data))// firstName and lastName will have correct typereturn (<form onSubmit={onSubmit}><label>First Name</label><input {...register("firstName")} /><label>Last Name</label><input {...register("lastName")} /><buttontype="button"onClick={() => {setValue("lastName", "luo") // ✅setValue("firstName", true) // ❌: true is not stringerrors.bill // ❌: property bill does not exist}}>SetValue</button></form>)}
設計と理念
React Hook Formの設計と理念は、ユーザーと開発者のエクスペリエンスに焦点を当てています。 このライブラリは、パフォーマンスの微調整とアクセシビリティの向上により、ユーザーによりスムーズなインタラクションエクスペリエンスを提供することを目指しています。 パフォーマンスの向上には、次のようなものがあります。
- プロキシを介したフォーム状態サブスクリプションモデルの導入
- 不要な計算の回避
- 必要な場合のコンポーネントの再レンダリングの分離
全体的に、ユーザーがアプリケーションと対話する際のユーザーエクスペリエンスが向上します。 開発者向けには、組み込みのバリデーションを導入し、HTML標準に厳密に準拠することで、強力なバリデーションメソッドによる拡張とスキーマバリデーションとのネイティブ統合を可能にします。 さらに、TypeScriptの助けを借りて強力に型チェックされたフォームを持つことで、開発者が堅牢なフォームソリューションを構築するための早期のビルド時フィードバックが提供されます。
Bill氏による以下の講演では、いくつかのアイデアと設計パターンが紹介されています。
ご支援ありがとうございます
React Hook Formがプロジェクトで役立つと思われる場合は、スターを付けてサポートをご検討ください。