Diese Seite stellt die grundlegenden Konzepte und Terminologie vor, die in der @tanstack/react-form Bibliothek verwendet werden. Wenn Sie sich mit diesen Konzepten vertraut machen, können Sie die Bibliothek besser verstehen und damit arbeiten.
Sie können Optionen für Ihr Formular erstellen, damit es von mehreren Formularen gemeinsam genutzt werden kann, indem Sie die Funktion formOptions verwenden.
Beispiel
interface User {
firstName: string
lastName: string
hobbies: Array<string>
}
const defaultUser: User = { firstName: '', lastName: '', hobbies: [] }
const formOpts = formOptions({
defaultValues: defaultUser,
})
interface User {
firstName: string
lastName: string
hobbies: Array<string>
}
const defaultUser: User = { firstName: '', lastName: '', hobbies: [] }
const formOpts = formOptions({
defaultValues: defaultUser,
})
Eine Formularinstanz ist ein Objekt, das ein einzelnes Formular repräsentiert und Methoden und Eigenschaften für die Arbeit mit dem Formular bereitstellt. Sie erstellen eine Formularinstanz mithilfe des useForm Hooks, der von den Formularoptionen bereitgestellt wird. Der Hook akzeptiert ein Objekt mit einer onSubmit Funktion, die aufgerufen wird, wenn das Formular übermittelt wird.
const form = useForm({
...formOpts,
onSubmit: async ({ value }) => {
// Do something with form data
console.log(value)
},
})
const form = useForm({
...formOpts,
onSubmit: async ({ value }) => {
// Do something with form data
console.log(value)
},
})
Sie können auch eine Formularinstanz erstellen, ohne formOptions zu verwenden, indem Sie die eigenständige useForm API verwenden.
interface User {
firstName: string
lastName: string
hobbies: Array<string>
}
const defaultUser: User = { firstName: '', lastName: '', hobbies: [] }
const form = useForm({
defaultValues: defaultUser,
onSubmit: async ({ value }) => {
// Do something with form data
console.log(value)
},
})
interface User {
firstName: string
lastName: string
hobbies: Array<string>
}
const defaultUser: User = { firstName: '', lastName: '', hobbies: [] }
const form = useForm({
defaultValues: defaultUser,
onSubmit: async ({ value }) => {
// Do something with form data
console.log(value)
},
})
Ein Feld repräsentiert ein einzelnes Formulareingabeelement, wie z. B. ein Textfeld oder eine Checkbox. Felder werden mit der form.Field Komponente erstellt, die von der Formularinstanz bereitgestellt wird. Die Komponente akzeptiert eine `name`-Prop, die mit einem Schlüssel in den Standardwerten des Formulars übereinstimmen muss. Sie akzeptiert auch eine `children`-Prop, die eine Render-Prop-Funktion ist, die ein Feldobjekt als Argument entgegennimmt.
Beispiel
<form.Field
name="firstName"
children={(field) => (
<>
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
/>
<form.Field
name="firstName"
children={(field) => (
<>
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
/>
Jedes Feld hat seinen eigenen Zustand, der seinen aktuellen Wert, seinen Validierungsstatus, Fehlermeldungen und andere Metadaten enthält. Sie können auf den Zustand eines Feldes über die Eigenschaft field.state zugreifen.
Beispiel
const {
value,
meta: { errors, isValidating },
} = field.state
const {
value,
meta: { errors, isValidating },
} = field.state
Es gibt vier Zustände in den Metadaten, die nützlich sein können, um zu sehen, wie der Benutzer mit einem Feld interagiert.
const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta
const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta

Nicht-persistenter dirty Zustand
Persistenter dirty Zustand
Wir haben uns für das persistente 'dirty'-Zustandsmodell entschieden. Um auch einen nicht-persistenten 'dirty'-Zustand zu unterstützen, führen wir ein zusätzliches Flag ein.
const { isDefaultValue, isTouched } = field.state.meta
// The following line will re-create the non-Persistent `dirty` functionality.
const nonPersistentIsDirty = !isDefaultValue
const { isDefaultValue, isTouched } = field.state.meta
// The following line will re-create the non-Persistent `dirty` functionality.
const nonPersistentIsDirty = !isDefaultValue

Die Feld-API ist ein Objekt, das an die Render-Prop-Funktion übergeben wird, wenn ein Feld erstellt wird. Es stellt Methoden zur Bearbeitung des Feldzustands bereit.
Beispiel
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
@tanstack/react-form bietet standardmäßig sowohl synchrone als auch asynchrone Validierung. Validierungsfunktionen können über die Prop validators an die form.Field Komponente übergeben werden.
Beispiel
<form.Field
name="firstName"
validators={{
onChange: ({ value }) =>
!value
? 'A first name is required'
: value.length < 3
? 'First name must be at least 3 characters'
: undefined,
onChangeAsync: async ({ value }) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
return value.includes('error') && 'No "error" allowed in first name'
},
}}
children={(field) => (
<>
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
/>
<form.Field
name="firstName"
validators={{
onChange: ({ value }) =>
!value
? 'A first name is required'
: value.length < 3
? 'First name must be at least 3 characters'
: undefined,
onChangeAsync: async ({ value }) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
return value.includes('error') && 'No "error" allowed in first name'
},
}}
children={(field) => (
<>
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
/>
Zusätzlich zu handgeschriebenen Validierungsoptionen unterstützen wir auch die Standard Schema Spezifikation.
Sie können ein Schema mit einer beliebigen der Bibliotheken definieren, die die Spezifikation implementieren, und es an einen Formular- oder Feldvalidator übergeben.
Unterstützte Bibliotheken umfassen:
import { z } from 'zod'
const userSchema = z.object({
age: z.number().gte(13, 'You must be 13 to make an account'),
})
function App() {
const form = useForm({
defaultValues: {
age: 0,
},
validators: {
onChange: userSchema,
},
})
return (
<div>
<form.Field
name="age"
children={(field) => {
return <>{/* ... */}</>
}}
/>
</div>
)
}
import { z } from 'zod'
const userSchema = z.object({
age: z.number().gte(13, 'You must be 13 to make an account'),
})
function App() {
const form = useForm({
defaultValues: {
age: 0,
},
validators: {
onChange: userSchema,
},
})
return (
<div>
<form.Field
name="age"
children={(field) => {
return <>{/* ... */}</>
}}
/>
</div>
)
}
@tanstack/react-form bietet verschiedene Möglichkeiten, Formular- und Feldzustandsänderungen zu abonnieren, insbesondere den useStore(form.store) Hook und die form.Subscribe Komponente. Diese Methoden ermöglichen es Ihnen, die Rendering-Leistung Ihres Formulars zu optimieren, indem Komponenten nur bei Bedarf aktualisiert werden.
Beispiel
const firstName = useStore(form.store, (state) => state.values.firstName)
//...
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? '...' : 'Submit'}
</button>
)}
/>
const firstName = useStore(form.store, (state) => state.values.firstName)
//...
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? '...' : 'Submit'}
</button>
)}
/>
Es ist wichtig zu beachten, dass die selector Prop des useStore Hooks zwar optional ist, aber es dringend empfohlen wird, eine anzugeben, da das Weglassen zu unnötigen Neurendern führt.
// Correct use
const firstName = useStore(form.store, (state) => state.values.firstName)
const errors = useStore(form.store, (state) => state.errorMap)
// Incorrect use
const store = useStore(form.store)
// Correct use
const firstName = useStore(form.store, (state) => state.values.firstName)
const errors = useStore(form.store, (state) => state.errorMap)
// Incorrect use
const store = useStore(form.store)
Hinweis: Die Verwendung des useField Hooks zur Erzielung von Reaktivität wird nicht empfohlen, da er dazu gedacht ist, sorgfältig innerhalb der form.Field Komponente verwendet zu werden. Sie sollten stattdessen useStore(form.store) verwenden.
@tanstack/react-form ermöglicht es Ihnen, auf spezifische Trigger zu reagieren und diese zu "lauschen", um Seiteneffekte auszulösen.
Beispiel
<form.Field
name="country"
listeners={{
onChange: ({ value }) => {
console.log(`Country changed to: ${value}, resetting province`)
form.setFieldValue('province', '')
},
}}
/>
<form.Field
name="country"
listeners={{
onChange: ({ value }) => {
console.log(`Country changed to: ${value}, resetting province`)
form.setFieldValue('province', '')
},
}}
/>
Weitere Informationen finden Sie unter Listeners
Array-Felder ermöglichen es Ihnen, eine Liste von Werten innerhalb eines Formulars zu verwalten, wie z. B. eine Liste von Hobbys. Sie können ein Array-Feld mit der form.Field Komponente mit der Prop mode="array" erstellen.
Wenn Sie mit Array-Feldern arbeiten, können Sie die Methoden pushValue, removeValue, swapValues und moveValue des Feldes verwenden, um Werte im Array hinzuzufügen, zu entfernen und zu tauschen.
Beispiel
<form.Field
name="hobbies"
mode="array"
children={(hobbiesField) => (
<div>
Hobbies
<div>
{!hobbiesField.state.value.length
? 'No hobbies found.'
: hobbiesField.state.value.map((_, i) => (
<div key={i}>
<form.Field
name={`hobbies[${i}].name`}
children={(field) => {
return (
<div>
<label htmlFor={field.name}>Name:</label>
<input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<button
type="button"
onClick={() => hobbiesField.removeValue(i)}
>
X
</button>
<FieldInfo field={field} />
</div>
)
}}
/>
<form.Field
name={`hobbies[${i}].description`}
children={(field) => {
return (
<div>
<label htmlFor={field.name}>Description:</label>
<input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</div>
)
}}
/>
</div>
))}
</div>
<button
type="button"
onClick={() =>
hobbiesField.pushValue({
name: '',
description: '',
yearsOfExperience: 0,
})
}
>
Add hobby
</button>
</div>
)}
/>
<form.Field
name="hobbies"
mode="array"
children={(hobbiesField) => (
<div>
Hobbies
<div>
{!hobbiesField.state.value.length
? 'No hobbies found.'
: hobbiesField.state.value.map((_, i) => (
<div key={i}>
<form.Field
name={`hobbies[${i}].name`}
children={(field) => {
return (
<div>
<label htmlFor={field.name}>Name:</label>
<input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<button
type="button"
onClick={() => hobbiesField.removeValue(i)}
>
X
</button>
<FieldInfo field={field} />
</div>
)
}}
/>
<form.Field
name={`hobbies[${i}].description`}
children={(field) => {
return (
<div>
<label htmlFor={field.name}>Description:</label>
<input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</div>
)
}}
/>
</div>
))}
</div>
<button
type="button"
onClick={() =>
hobbiesField.pushValue({
name: '',
description: '',
yearsOfExperience: 0,
})
}
>
Add hobby
</button>
</div>
)}
/>
Wenn Sie <button type="reset"> in Verbindung mit form.reset() von TanStack Form verwenden, müssen Sie das Standardverhalten von HTML-Resets verhindern, um unerwartete Resets von Formularelementen (insbesondere <select>-Elementen) auf ihre ursprünglichen HTML-Werte zu vermeiden. Verwenden Sie event.preventDefault() innerhalb des onClick-Handlers des Buttons, um den nativen Formular-Reset zu verhindern.
Beispiel
<button
type="reset"
onClick={(event) => {
event.preventDefault()
form.reset()
}}
>
Reset
</button>
<button
type="reset"
onClick={(event) => {
event.preventDefault()
form.reset()
}}
>
Reset
</button>
Alternativ können Sie <button type="button"> verwenden, um den nativen HTML-Reset zu verhindern.
<button
type="button"
onClick={() => {
form.reset()
}}
>
Reset
</button>
<button
type="button"
onClick={() => {
form.reset()
}}
>
Reset
</button>
Dies sind die grundlegenden Konzepte und die Terminologie, die in der @tanstack/react-form Bibliothek verwendet werden. Das Verständnis dieser Konzepte wird Ihnen helfen, effektiver mit der Bibliothek zu arbeiten und komplexe Formulare mühelos zu erstellen.
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.