Watch now

React Hook Form – Ein umfassender Leitfaden

Je nach Anwendungsfall kann die Implementierung von React Hook Forms recht komplex sein. Deshalb haben wir diesen Leitfaden geschrieben, um dir den Einstieg zu erleichtern.
Aagam Vadecha

Written by Aagam 

Jul 20, 2026
React hook form

#Was ist React Hook Form

Die meisten Anwendungen verfügen über Formulare zur Datenerfassung. Je nach Anwendungsfall kann die Implementierung von Formularen ziemlich komplex werden, insbesondere beim Erstellen von Enterprise-Anwendungen, die eine intuitive und einwandfreie Nutzererfahrung bieten sollen. Als Entwickler oder Entwicklerin bist du in den meisten deiner Projekte höchstwahrscheinlich schon einmal auf das Thema Formularerstellung gestoßen. Einfache Formulare lassen sich natürlich auch selbst verwalten, aber ab einem bestimmten Punkt ist es sinnvoll, eine Bibliothek zu verwenden, die einen Großteil der Arbeit beim Umgang mit komplexen Formularen abstrahiert.

React Hook Form ist eine solche Bibliothek, die bei der Verwaltung komplexer Formulare hilft. Sie bietet eine hervorragende Performance, ist extrem leichtgewichtig, kommt ohne Abhängigkeiten aus, lässt sich problemlos in verschiedene React-UI-Frameworks wie Material oder AntD integrieren und bietet eine intuitive API.

#Wie man React Hook Form verwendet

Installiere die Bibliothek zunächst mit npm i --save react-hook-form

Die Verwendung innerhalb deiner Komponente ist denkbar einfach: Importiere den useForm-Hook aus der Bibliothek

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

Der useForm-Hook gibt uns Zugriff auf viele Eigenschaften. Zunächst verwenden wir nur register und handleSubmit. Destrukturiere diese innerhalb deiner funktionalen Komponente

const { register, handleSubmit } = useForm();

Registriere ein Eingabeelement mit einem Variablennamen name wie folgt. Dadurch wird der Wert des Eingabefelds für die Formularvalidierung und -übermittlung verfügbar gemacht.

<input
className="border-2 outline-none p-2 rounded-md"
placeholder="Name"
{...register("name")}
/>

Anschließend kannst du das Absenden deines Formulars auf diese Weise handhaben und eine onSubmit-Methode erstellen, die Zugriff auf die Formulardaten hat.

<form onSubmit={handleSubmit(onSubmit)}>

Nachfolgend findest du ein vollständiges Beispiel

import { useState } from "react";
import { useForm } from "react-hook-form";
export default function ReactHookFormMini() {
const { register, handleSubmit } = useForm();
const [data, setData] = useState("");
const onSubmit = (data) => {
setData(data)
}
return (
<div className="w-full flex justify-center items-center bg-gray-900 p-8 border-r border-dashed">
<div className="w-1/2 shadow-lg rounded-md bg-white p-8 flex flex-col" style={{height:'375px'}}>
<h2 className="text-center font-medium text-2xl mb-4">
React Hook Form Basic
</h2>
<form
onSubmit={handleSubmit(onSubmit)}
className="flex flex-1 flex-col justify-evenly"
>
<input
className="border-2 outline-none p-2 rounded-md"
placeholder="Name"
{...register("name")}
/>
<button
className=" flex justify-center p-2 rounded-md w-1/2 self-center bg-gray-900 text-white hover:bg-gray-800"
type='submit'
>
<span>
Submit
</span>
</button>
</form>
<div className='h-4'>
<p> Data: {JSON.stringify(data)}</p>
</div>
</div>
</div>
);
}

So wird es aussehen. Wir haben Tailwind für das CSS verwendet, du kannst aber gerne deine eigenen CSS-Frameworks nutzen.

A basic React Hook Form example showing a name input, a submit button, and the resulting JSON data object being displayed

#Validierungen hinzufügen

Validierungen sind fester Bestandteil nahezu jedes Formulars – sie sind die erste Verteidigungslinie einer Anwendung gegen unerwünschte Daten. Validierungen stellen sicher, dass fehlerhafte Daten nicht bis zu den Backend-Servern und letztlich zu den Datenbanken vordringen. Idealerweise werden Daten in den meisten Softwaresystemen auf jeder Ebene validiert, also im Frontend, im Backend und in der Datenbank.

Bei großen Formularen kann es mühsam und repetitiv werden, Validierungen für jedes einzelne Feld sowie deren Fehlerzustände zu verwalten. React Hook Form bietet hervorragende API-Optionen und orientiert sich zudem am bestehenden HTML-Standard für die Formularvalidierung. Hier findest du die Liste der von der Bibliothek unterstützten Validierungsregeln:

  • required – Legt fest, ob der Eingabewert erforderlich ist
  • min – Der minimale Wert, der akzeptiert werden kann
  • max – Der maximale Wert, der akzeptiert werden kann
  • minLength – Die minimale Länge der Eingabe, die akzeptiert werden kann
  • maxLength – Die maximale Länge der Eingabe, die akzeptiert werden kann
  • pattern – Ein Regex-Muster zur Validierung der Eingabe
  • validate – Eine beliebige benutzerdefinierte Funktion zur Validierung der Eingabe

Ein einfaches Beispiel zur Verwendung dieser Attribute

<input
className="border-2 outline-none p-2 rounded-md"
placeholder="Phone Number"
{...register("phoneNumber", {
minLength: 1,
maxLength: 10,
})}
/>

Außerdem kannst du Fehlermeldungen direkt zusammen mit der Validierungsregel übergeben, wodurch die Anzeige von Fehlern sehr einfach wird.

<input
className="border-2 outline-none p-2 rounded-md"
placeholder="Email"
{...register("email", {
pattern: {
value: /^.*@hygraph.com$/,
message: 'Email must end with hygraph.com'
}
})}
/>

Du kannst das Fehlerobjekt aus useFrom abrufen und die Fehlermeldung dann im Template anzeigen.

const { formState: { errors } } = useForm();
<span className="text-sm text-red-700">
{errors?.email?.message}
</span>

A React Hook Form demonstrating built-in validation with a red error message appearing for an invalid email input

#Bibliotheken zur Schema-Validierung

React Hook Form unterstützt außerdem die Integration mit bekannten Bibliotheken zur Schema-Validierung. Du kannst Bibliotheken wie Zod, Joi oder Yup zusammen mit React Hook Form in deinen Formularen einsetzen. Schauen wir uns ein Beispiel mit der Schema-Validierungsbibliothek Yup an.

Zunächst müssen wir unser Formulardatenschema wie unten gezeigt deklarieren

// ...
const schema = yup
.object({
fullName: yup.string().required(),
age: yup.number().positive().integer().required(),
})
.required();
// ...

Anschließend können wir den Yup-Resolver aus Yup importieren und ihn an die useForm-Methode von React Hook Form übergeben.

import { yupResolver } from "@hookform/resolvers/yup";
// ...
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
// ...

Hier ist ein vollständiges Beispiel

import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
const schema = yup
.object({
fullName: yup.string().required(),
age: yup.number().positive().integer().required(),
})
.required();
export default function YupExample() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("fullName")} />
<p>{errors.fullName?.message}</p>
<input {...register("age")} />
<p>{errors.age?.message}</p>
<input type="submit" />
</form>
);
}

#Integration mit anderen Komponenten

Es ist durchaus möglich, dass in deinem Projekt bereits UI-Frameworks eingerichtet sind und du UI-Komponenten aus dieser Bibliothek verwendest. React Hook Form lässt sich auch mit solchen UI-Frameworks integrieren. Im folgenden Beispiel siehst du, wie React Hook Form mit den Eingabekomponenten von AntD integriert werden kann.

import React, { useState } from 'react';
import { Controller, useForm } from "react-hook-form";
import { Input, Checkbox, Slider } from "antd";
export default function RFHWithAntd() {
const { control, handleSubmit } = useForm();
const [data, setData] = useState({});
const onSubmit = (data) => {
setData(data)
}
return (
<div className="w-full flex justify-center items-center bg-gray-900 p-8 border-r border-dashed">
<div className="w-1/2 shadow-lg rounded-md bg-white p-8 flex flex-col" style={{ height: '375px' }}>
<h2 className="text-center font-medium text-2xl mb-4">
React Hook Form With AntD
</h2>
<form
onSubmit={handleSubmit(onSubmit)}
className="flex flex-1 flex-col justify-evenly"
>
<Controller
control={control}
name="name"
render={({ field }) => (
<Input
{...field}
placeholder="Name"
/>
)}
/>
<div className="flex">
<label>Is Developer?</label>
<Controller
control={control}
name="isDeveloper"
render={({ field: { value, onChange } }) => (
<Checkbox
className="ml-4"
checked={value}
onChange={(e) => {
onChange(e.target.checked);
}}
/>
)}
/></div>
<section>
<label>Experience In Years</label>
<Controller
control={control}
name="experience"
render={({ field }) => <Slider {...field} />}
/>
</section>
<button
className=" flex justify-center p-2 rounded-md w-1/2
self-center bg-gray-900 text-white hover:bg-gray-800"
type='submit'
>
<span>
Submit
</span>
</button>
</form>
<div className='h-4'>
<p> Data: {JSON.stringify(data)}</p>
</div>
</div>
</div>
)
};

React Hook Form integrated with AntD, showing a form with a checkbox and slider, and the resulting submitted JSON data

#React Hook Form-Beispiele

Typescript

React Hook Form unterstützt TypeScript, was unserem Code zusätzliche Typsicherheit verleiht. Wir können die Typen für unsere Formulardaten definieren und sie wie unten gezeigt an React Hook Form übergeben

import { useForm } from "react-hook-form"
type FormData = {
firstName: string
age: number
}
export default function TypeScriptExample() {
// ...
const {
register,
setValue,
handleSubmit,
formState: { errors },
} = useForm<FormData>()
const onSubmit = handleSubmit((data) => console.log(data))
return (
// ...
)
}

Das war's schon. Jetzt weiß React Hook Form, wie unsere Formulardaten aussehen, und versucht, jegliche Typverstöße zu verhindern. Wenn wir beispielsweise den folgenden Code in das Markup des TypeScript-Formulars einfügen, zeigt es uns einen Typfehler an, der besagt, dass die Eigenschaft name im Typ FormData nicht existiert

return (
// ...
{errors.name?.message}
// ...
)

Performance-Vergleich

Wir haben bereits erwähnt, dass React Hook Form eine hervorragende Performance bietet. Einer der Gründe dafür liegt darin, wie die Bibliothek mit Re-Renders umgeht. Im Vergleich zu jeder anderen Bibliothek oder einer von Grund auf selbst implementierten Formularlösung in React führt React Hook Form kaum Re-Renders durch, wenn sich Werte innerhalb deines Formulars ändern – eine großartige Optimierung, die von Haus aus mitgeliefert wird. Wir können das anhand eines Beispiels nachvollziehen: Wir erstellen zwei Formulare mit derselben Funktionalität. Eines mit einer Implementierung von Grund auf und eines mit React Hook Form, und vergleichen anschließend die Re-Renders bei derselben Eingabe.

Normales Formular

import React, { useState } from 'react';
let renderCount = 0
export default function NormalForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [showFormData, setShowFormData] = useState(false)
const onSubmit = (event) => {
event.preventDefault()
setShowFormData(true)
console.log('Run Validations Manually, maintain & show errors on UI, if all good make API call.')
}
renderCount += 1
return (
<div className="w-1/2 flex justify-center items-center bg-gray-900 p-8">
<div className="w-full shadow-lg rounded-md bg-white p-8 flex flex-col" style={{ height: '375px' }}>
<h2 className="text-center font-medium text-2xl mb-4">
Normal Form
</h2>
Render Count -- {renderCount}
<form
onSubmit={onSubmit}
className="flex flex-1 flex-col justify-evenly"
>
<input
className="border-2 outline-none p-2 rounded-md"
placeholder="Name"
value={name}
onChange={(e) => { setName(e.target.value) }}
/>
<input
className="border-2 outline-none p-2 rounded-md"
type="email"
placeholder="Email"
value={email}
onChange={(e) => { setEmail(e.target.value) }}
/>
<button
className=" flex justify-center p-2 rounded-md
w-1/2 self-center bg-gray-900 text-white hover:bg-gray-800"
type='submit'
>
<span>
Submit
</span>
</button>
</form>
{
<div className='h-4'>
<p> Data:
{
showFormData ?
<span> {name} {email} </span>
: null
}
</p>
</div>
}
</div>
</div>
);
}

React Hook Form

import { useState } from "react";
import { useForm } from "react-hook-form";
let renderCount = 0
export default function ReactHookForm() {
const { register, handleSubmit } = useForm();
const [data, setData] = useState("");
const onSubmit = (data) => {
setData(JSON.stringify(data))
}
renderCount += 1
return (
<div className="w-1/2 flex justify-center items-center bg-gray-900 p-8 border-r border-dashed">
<div className="w-full shadow-lg rounded-md bg-white p-8 flex flex-col" style={{ height: '375px' }}>
<h2 className="text-center font-medium text-2xl mb-4">
React Hook Form
</h2>
Render Count -- {renderCount}
<form
onSubmit={handleSubmit(onSubmit)}
className="flex flex-1 flex-col justify-evenly"
>
<input
className="border-2 outline-none p-2 rounded-md"
placeholder="Name"
{...register("name")}
/>
<input
className="border-2 outline-none p-2 rounded-md"
placeholder="Email"
{...register("email")}
/>
<button
className=" flex justify-center p-2 rounded-md
w-1/2 self-center bg-gray-900 text-white hover:bg-gray-800"
type='submit'
>
<span>
Submit
</span>
</button>
</form>
<div className='h-4'>
<p> Data: {data}</p>
</div>
</div>
</div>
);
}

Zu Beginn, ohne jegliche Eingaben im Formular.

Side-by-side comparison of React Hook Form vs. a normal form, demonstrating how React Hook Form minimizes re-renders

Nach dem Eingeben derselben Werte in das Formular und dem Absenden.

React Hook Form performance benefit shown, with its Render Count at 4 compared to 58 for a Normal Form after user input

React Hook Form benötigte 4 Re-Renders, während das normale Formular 58 benötigte – der Unterschied ist erheblich. Zudem handelt es sich hierbei um ein sehr einfaches Formular mit nur zwei Feldern, sodass man sich vorstellen kann, dass die Re-Renders bei einem komplexen Formular noch deutlich zahlreicher ausfallen.

Weiterführendes Beispiel

Um unser Verständnis zu vertiefen, können wir noch einen Schritt weitergehen und die übrigen verfügbaren API-Optionen erkunden. Der useForm-Hook bietet eine formState-Eigenschaft, die uns weitere Details zur Interaktion der Nutzerinnen und Nutzer mit unserem Formular liefert.

  • isDirty: boolescher Wert, der angibt, ob der Nutzer mit dem Formular interagiert hat
  • isValid: boolescher Wert, der angibt, ob der aktuelle Formularzustand gültig ist.
  • errors: ein Objekt, das Fehler enthält, falls eine der Validierungen fehlschlägt.
  • isSubmitted: boolescher Wert, der angibt, ob der Nutzer mindestens einmal versucht hat, das Formular abzusenden
  • touchedFields: ein Objekt, das die berührten Felder enthält.
  • dirtyFields: ein Objekt, das die geänderten Felder enthält.

Der Unterschied zwischen dirty und touched Feldern besteht darin, dass ein Feld als touched markiert wird, sobald der Nutzer auf ein Texteingabefeld klickt – jedoch noch nicht als dirty. Erst wenn der Nutzer anschließend auch einen Wert in das Texteingabefeld eingibt, wird es als dirty markiert.

Der useForm-Hook bietet außerdem eine watch-Funktion, mit der Formulareingaben beobachtet und andere Felder dynamisch angezeigt werden können. Dynamische Formulare sind ein häufiger Anwendungsfall, bei dem Formularfelder dynamisch angezeigt werden, je nachdem, was der Nutzer in vorherige Felder eingibt.

Hier ist ein vollständiges, fortgeschrittenes Beispiel, das die Verwendung aller oben genannten Eigenschaften zeigt.

import { useState } from 'react';
import { useForm } from 'react-hook-form';
let renderCount = 0
export default function ReactHookFormAdvanced() {
const {
register,
handleSubmit,
formState: { touchedFields, isDirty, isValid, dirtyFields, isSubmitted, errors },
watch
} = useForm();
const [data, setData] = useState('');
const watchIsDeveloper = watch('isDeveloper');
renderCount += 1
return (
<div className='w-full flex justify-center items-center bg-gray-900 p-8'>
<div className='w-2/3 shadow-lg rounded-md bg-white p-8 flex flex-col justify-start' style={{ height: '700px' }}>
<h2 className='text-center font-medium text-2xl mb-4'>
React Hook Form Advanced
</h2>
Render Count -- {renderCount}
<form
onSubmit={handleSubmit(setData)}
className='flex flex-1 flex-col justify-evenly'
>
<input
className='border-2 outline-none p-2 rounded-md'
placeholder='Name'
{...register('name')}
/>
<input
className='border-2 outline-none p-2 rounded-md'
placeholder='Email'
{...register('email', { required: 'Email is required.' })}
/>
<input
className='border-2 outline-none p-2 rounded-md'
placeholder='Phone Number'
{...register('phoneNumber')}
/>
<div>
<span className='mr-4'>
Are you a developer?
</span>
<input type='checkbox' {...register('isDeveloper')} />
</div>
{
watchIsDeveloper ?
<div className='flex w-full '>
<input
className='flex-1 border-2 outline-none p-2 rounded-md mr-2'
placeholder='Experience (Years)'
{...register('exp_years')} />
<input
className='flex-1 border-2 outline-none p-2 rounded-md'
placeholder='Experience (Months)'
{...register('exp_months')} />
</div>
: null
}
<button
className=' flex justify-center p-2 rounded-md
w-1/2 self-center bg-gray-900 text-white hover:bg-gray-800'
type='submit'
>
<span>
Submit
</span>
</button>
</form>
<p className='w-4/5'> <strong> Data: </strong> {JSON.stringify(data)} </p>
<p> <strong> Is Valid: </strong> {JSON.stringify(isValid)}</p>
<p> <strong> Is Dirty : </strong> {JSON.stringify(isDirty)} </p>
<p> <strong> Is Submited: </strong> {JSON.stringify(isSubmitted)}</p>
<p> <strong> Errors: </strong> {JSON.stringify(errors?.email?.message)}</p>
<p> <strong> Dirty Fields : </strong> {JSON.stringify(dirtyFields)} </p>
<p> <strong> Touched Fields: </strong> {JSON.stringify(touchedFields)} </p>
<p> <strong> Watching Is Developer: </strong> {JSON.stringify(watchIsDeveloper)}</p>
</div>
</div>
);
}

Advanced React Hook Form example showing real-time tracking of form state properties like 'isValid', 'isDirty', and 'isSubmitted

Advanced React Hook Form showing a conditional 'Experience' field and tracking 'isDirty' and 'isValid' form states

Blog Author

Aagam Vadecha

Aagam Vadecha

As a Software Engineer, my daily routine revolves around writing scalable applications with clean code & maintaining them. In my spare time, I love to explore software architecture patterns, write tech articles & watch thrillers!

Share with others

Sign up for our newsletter!

Be the first to know about releases and industry news and insights.