コンテンツにスキップ

スタートガイド

React Hook Formを使ったシンプルなフォームバリデーション。

インストール

React Hook Formのインストールは、1つのコマンドを実行するだけで完了します。

npm install react-hook-form

以下のコードは、基本的な使用例を示しています。

import { useForm, SubmitHandler } from "react-hook-form"
type Inputs = {
example: string
exampleRequired: 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 it
return (
/* "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>
)
}
import { useForm } from "react-hook-form"
export default function App() {
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm()
const onSubmit = (data) => console.log(data)
console.log(watch("example")) // watch input value by passing the name of it
return (
/* "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: string
gender: 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>
)
}
import { useForm } from "react-hook-form"
export default function App() {
const { register, handleSubmit } = useForm()
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} />
<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: string
lastName: string
age: 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>
)
}
import { useForm } from "react-hook-form"
export default function App() {
const { register, handleSubmit } = useForm()
const onSubmit = (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": string
Age: number
}
type InputProps = {
label: Path<IFormValues>
register: UseFormRegister<IFormValues>
required: boolean
}
// The following component is an example of your existing Input Component
const Input = ({ label, register, required }: InputProps) => (
<>
<label>{label}</label>
<input {...register(label, { required })} />
</>
)
// you can use React.forwardRef to pass the ref too
const 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>
)
}
import { useForm } from "react-hook-form"
// The following component is an example of your existing Input Component
const Input = ({ label, register, required }) => (
<>
<label>{label}</label>
<input {...register(label, { required })} />
</>
)
// you can use React.forwardRef to pass the ref too
const Select = React.forwardRef(({ 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()
const onSubmit = (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: string
lastName: string
iceCreamType: { 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)}>
<Controller
name="firstName"
control={control}
render={({ field }) => <Input {...field} />}
/>
<Controller
name="iceCreamType"
control={control}
render={({ field }) => (
<Select
{...field}
options={[
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" },
]}
/>
)}
/>
<input type="submit" />
</form>
)
}
import Select from "react-select"
import { useForm, Controller } from "react-hook-form"
import { Input } from "@material-ui/core"
const App = () => {
const { control, handleSubmit } = useForm({
defaultValues: {
firstName: "",
select: {},
},
})
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="firstName"
control={control}
render={({ field }) => <Input {...field} />}
/>
<Controller
name="select"
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-SelectAntDMUIなどの外部の制御されたコンポーネントを扱うことは避けられません。 これを簡単にするために、ラッパーコンポーネントであるControllerを提供し、統合プロセスを合理化すると同時に、カスタム登録を使用する自由を提供します。

コンポーネントAPIの使用

import { useForm, Controller, SubmitHandler } from "react-hook-form"
import { TextField, Checkbox } from "@material-ui/core"
interface IFormInputs {
TextField: string
MyCheckbox: 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)}>
<Controller
name="MyCheckbox"
control={control}
rules={{ required: true }}
render={({ field }) => <Checkbox {...field} />}
/>
<input type="submit" />
</form>
)
}
import { TextField } from "@material-ui/core"
import { useController, useForm } from "react-hook-form"
function Input({ control, name }) {
const {
field,
fieldState: { invalid, isTouched, isDirty },
formState: { touchedFields, dirtyFields },
} = useController({
name,
control,
rules: { required: true },
})
return (
<TextField
onChange={field.onChange} // send value to hook form
onBlur={field.onBlur} // notify when input is touched/blur
value={field.value} // input value
name={field.name} // send down the input name
inputRef={field.ref} // send input ref, so we can focus on input when error appear
/>
)
}

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 { TextField } from "@material-ui/core"
import { useController, useForm } from "react-hook-form"
function Input({ control, name }) {
const {
field,
fieldState: { invalid, isTouched, isDirty },
formState: { touchedFields, dirtyFields },
} = useController({
name,
control,
rules: { required: true },
})
return (
<TextField
onChange={field.onChange} // send value to hook form
onBlur={field.onBlur} // notify when input is touched/blur
value={field.value} // input value
name={field.name} // send down the input name
inputRef={field.ref} // send input ref, so we can focus on input when error appear
/>
)
}

グローバル状態との統合

このライブラリは状態管理ライブラリに依存する必要はありませんが、簡単に統合できます。

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 store
const onSubmit = (data) => props.updateAction(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<input type="submit" />
</form>
)
}
// Connect your component with redux
connect(
({ 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 (
<Form
action="/api/save" // Send post request with the FormData
// encType={'application/json'} you can also switch to json object
onSuccess={() => {
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>
)
}

スキーマバリデーション

YupZodSuperstructJoiを使用したスキーマベースのフォームバリデーションもサポートしています。`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` でラップします。

Expo JS
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>
<Controller
control={control}
rules={{
required: true,
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
placeholder="First name"
onBlur={onBlur}
onChangeText={onChange}
value={value}
/>
)}
name="firstName"
/>
{errors.firstName && <Text>This is required.</Text>}
<Controller
control={control}
rules={{
maxLength: 100,
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
placeholder="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: string
lastName: 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 type
return (
<form onSubmit={onSubmit}>
<label>First Name</label>
<input {...register("firstName")} />
<label>Last Name</label>
<input {...register("lastName")} />
<button
type="button"
onClick={() => {
setValue("lastName", "luo") // ✅
setValue("firstName", true) // ❌: true is not string
errors.bill // ❌: property bill does not exist
}}
>
SetValue
</button>
</form>
)
}

設計と理念

React Hook Formの設計と理念は、ユーザーと開発者のエクスペリエンスに焦点を当てています。 このライブラリは、パフォーマンスの微調整とアクセシビリティの向上により、ユーザーによりスムーズなインタラクションエクスペリエンスを提供することを目指しています。 パフォーマンスの向上には、次のようなものがあります。

  • プロキシを介したフォーム状態サブスクリプションモデルの導入
  • 不要な計算の回避
  • 必要な場合のコンポーネントの再レンダリングの分離

全体的に、ユーザーがアプリケーションと対話する際のユーザーエクスペリエンスが向上します。 開発者向けには、組み込みのバリデーションを導入し、HTML標準に厳密に準拠することで、強力なバリデーションメソッドによる拡張とスキーマバリデーションとのネイティブ統合を可能にします。 さらに、TypeScriptの助けを借りて強力に型チェックされたフォームを持つことで、開発者が堅牢なフォームソリューションを構築するための早期のビルド時フィードバックが提供されます。

Bill氏による以下の講演では、いくつかのアイデアと設計パターンが紹介されています。

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

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