Eine Möglichkeit, mit langen, komplexen Formularen umzugehen, besteht darin, sie in mehrere Schritte aufzuteilen. Sie wissen schon, eine Reihe von Fragen beantworten, zur nächsten übergehen, dann vielleicht zu einer weiteren und so weiter. Wir bezeichnen diese oft als Mehrschrittformulare (aus offensichtlichen Gründen), aber andere nennen sie auch "Wizard"-Formulare.
Mehrschrittformulare können eine großartige Idee sein! Indem nur wenige Eingaben gleichzeitig auf einem Bildschirm angezeigt werden, kann das Formular verdaulicher erscheinen und verhindern, dass Benutzer von einer Flut von Formularfeldern überwältigt werden. Obwohl ich es nicht nachgeschlagen habe, bin ich bereit zu sagen, dass niemand Spaß daran hat, ein riesiges Formular auszufüllen – hier können Mehrschrittformulare nützlich sein.
Das Problem ist, dass sich Mehrschrittformulare – obwohl sie die wahrgenommene Komplexität im Frontend reduzieren – in der Entwicklung komplex und überwältigend anfühlen können. Aber ich bin hier, um Ihnen zu sagen, dass dies nicht nur erreichbar, sondern auch relativ einfach ist, wenn React als Basis verwendet wird. Das werden wir also heute gemeinsam bauen!
Hier ist das Endergebnis:
Lasst es uns bauen!
Der einfachste Weg, ein Mehrschrittformular zu erstellen, besteht darin, ein Container-Formularelement zu erstellen, das alle Schritte als Komponenten darin enthält. Hier ist eine visuelle Darstellung dieses Containers (), der darin enthaltenen Komponenten (, , ) und der Art und Weise, wie Zustände und Props zwischen ihnen übergeben werden.

dient als Container, während drei Kindkomponenten darin als jeder Schritt des Formulars fungieren.Obwohl es komplexer erscheint als ein reguläres Formular, verwendet ein Mehrschrittformular immer noch die gleichen Prinzipien wie ein React-Formular
- Zustand wird zum Speichern von Daten und Benutzereingaben verwendet.
- Komponente wird zum Schreiben von Methoden und der Benutzeroberfläche verwendet.
- Props werden zum Übergeben von Daten und Funktionen an Elemente verwendet.
Anstatt einer Formular-Komponente werden wir eine Eltern-Komponente und drei Kind-Komponenten haben. In der obigen Abbildung sendet Daten und Funktionen über Props an die Kind-Komponenten, und im Gegenzug lösen die Kind-Komponenten eine handleChange()-Funktion aus, um Werte im Zustand von festzulegen. Das ist eine große glückliche Familie hier! Wir brauchen auch eine Funktion, um das Formular von einem Schritt zum nächsten zu bewegen, und dazu kommen wir etwas später.
Die Schritt-Kind-Komponenten (verstehen Sie?) erhalten Props von der Eltern-Komponente für die Props value und onChange.
-Komponente rendert eine E-Mail-Adressen-Eingaberendert eine Benutzernamen-Eingaberendert eine Passwort-Eingabe und eine Senden-Schaltfläche
liefert sowohl Daten als auch Funktionen in Kind-Komponenten, und Kind-Komponenten geben Benutzereingaben über seine props an die Eltern zurück.
Erstellen der Schritt-Kind-Komponenten
Zuerst erstellen wir die Kind-Komponenten des Formulars. Wir halten die Dinge für dieses Beispiel recht einfach, indem wir nur eine Eingabe pro Schritt verwenden, aber jeder Schritt könnte wirklich so komplex sein, wie wir möchten. Da die Kind-Komponenten untereinander fast gleich aussehen, zeige ich hier nur eine davon. Aber schauen Sie sich unbedingt die Demo für den vollständigen Code an.
class Step1 extends React.Component {render() {
if (this.props.currentStep !== 1) { // Prop: The current step
return null
}
// The markup for the Step 1 UI
return(
<div className="form-group">
<label htmlFor="email">Email address</label>
<input
className="form-control"
id="email"
name="email"
type="text"
placeholder="Enter email"
value={this.props.email} // Prop: The email input data
onChange={this.props.handleChange} // Prop: Puts data into state
/>
</div>
)}
}
Jetzt können wir diese Kind-Komponente in die render()-Funktion des Formulars einfügen und die notwendigen Props übergeben. Genau wie in der Formular-Dokumentation von React können wir immer noch handleChange() verwenden, um die vom Benutzer gesendeten Daten mit setState() in den Zustand zu bringen. Eine handleSubmit()-Funktion wird beim Absenden des Formulars ausgeführt.
Als nächstes die Eltern-Komponente
Lassen Sie uns die Eltern-Komponente erstellen – die wir alle, wie wir jetzt wissen, nennen – und ihren Zustand und ihre Methoden initialisieren.
Wir verwenden einen currentStep-Zustand, der mit einem Standardwert von 1 initialisiert wird, was den ersten Schritt () des Formulars anzeigt. Wir werden den Zustand aktualisieren, während das Formular fortschreitet, um den aktuellen Schritt anzuzeigen.
class MasterForm extends Component {
constructor(props) {
super(props)
// Set the initial input values
this.state = {
currentStep: 1, // Default is Step 1
email: '',
username: '',
password: '',
}
// Bind the submission to handleChange()
this.handleChange = this.handleChange.bind(this)
}
// Use the submitted data to set the state
handleChange(event) {
const {name, value} = event.target
this.setState({
[name]: value
})
}
// Trigger an alert on form submission
handleSubmit = (event) => {
event.preventDefault()
const { email, username, password } = this.state
alert(`Your registration detail: \n
Email: ${email} \n
Username: ${username} \n
Password: ${password}`)
}
// Render UI will go here...
}
OK, das ist die Basisfunktionalität, die wir suchen. Als Nächstes möchten wir die Shell-Benutzeroberfläche für das eigentliche Formular erstellen und die Kind-Komponenten darin aufrufen, einschließlich der erforderlichen Zustand-Props, die von über handleChange() übergeben werden.
render() {
return (
<React.Fragment>
<h1>A Wizard Form!</h1>
Step {this.state.currentStep}
<form onSubmit={this.handleSubmit}>
// Render the form steps and pass in the required props
<Step1
currentStep={this.state.currentStep}
handleChange={this.handleChange}
email={this.state.email}
/>
<Step2
currentStep={this.state.currentStep}
handleChange={this.handleChange}
username={this.state.username}
/>
<Step3
currentStep={this.state.currentStep}
handleChange={this.handleChange}
password={this.state.password}
/>
</form>
</React.Fragment>
)
}
Ein Schritt nach dem anderen
Bisher haben wir den Benutzern erlaubt, die Formularfelder auszufüllen, aber wir haben keine tatsächliche Möglichkeit geboten, zum nächsten Schritt zu gelangen oder zum vorherigen zurückzukehren. Das erfordert Vorwärts- und Rückwärtsfunktionen, die prüfen, ob der aktuelle Schritt einen vorherigen oder nächsten Schritt hat; und wenn ja, wird die currentStep-Prop entsprechend hoch- oder runtergeschoben.
class MasterForm extends Component {
constructor(props) {
super(props)
// Bind new functions for next and previous
this._next = this._next.bind(this)
this._prev = this._prev.bind(this)
}
// Test current step with ternary
// _next and _previous functions will be called on button click
_next() {
let currentStep = this.state.currentStep
// If the current step is 1 or 2, then add one on "next" button click
currentStep = currentStep >= 2? 3: currentStep + 1
this.setState({
currentStep: currentStep
})
}
_prev() {
let currentStep = this.state.currentStep
// If the current step is 2 or 3, then subtract one on "previous" button click
currentStep = currentStep <= 1? 1: currentStep - 1
this.setState({
currentStep: currentStep
})
}
}
Wir werden eine get-Funktion verwenden, die prüft, ob der aktuelle Schritt 1 oder 3 ist. Das liegt daran, dass wir ein dreistufiges Formular haben. Natürlich können wir diese Prüfungen ändern, wenn weitere Schritte zum Formular hinzugefügt werden. Wir wollen auch die nächsten und vorherigen Schaltflächen nur anzeigen, wenn es tatsächlich nächste und vorherige Schritte gibt, zu denen navigiert werden kann.
// The "next" and "previous" button functions
get previousButton(){
let currentStep = this.state.currentStep;
// If the current step is not 1, then render the "previous" button
if(currentStep !==1){
return (
<button
className="btn btn-secondary"
type="button"
onClick={this._prev}>
Previous
</button>
)
}
// ...else return nothing
return null;
}
get nextButton(){
let currentStep = this.state.currentStep;
// If the current step is not 3, then render the "next" button
if(currentStep <3){
return (
<button
className="btn btn-primary float-right"
type="button"
onClick={this._next}>
Next
</button>
)
}
// ...else render nothing
return null;
}
Alles, was übrig bleibt, ist, diese Schaltflächen zu rendern
// Render "next" and "previous" buttons
render(){
return(
<form onSubmit={this.handleSubmit}>
{/*
... other codes
*/}
{this.previousButton}
{this.nextButton}
</form>
)
}
Glückwunsch, Sie sind ein Formular-Zauberer! 🧙
Das war der letzte Schritt in diesem Mehrschritt-Tutorial zu Mehrschrittformularen. Wow, wie meta! Obwohl wir nicht tief in die Gestaltung eingedrungen sind, hoffe ich, dass Ihnen dies einen soliden Überblick darüber gibt, wie Sie komplexe Formulare weniger ... komplex machen können!
Hier ist noch einmal die endgültige Demo, damit Sie den gesamten Code in seinem vollen und gloriousen Kontext sehen können
React wurde für solche Dinge entwickelt, da es Zustände, Eigenschaftsänderungen, wiederverwendbare Komponenten und dergleichen nutzt. Ich weiß, dass React für manche Leute eine hohe Einstiegshürde sein kann, aber ich habe ein Buch geschrieben, das es zu einer viel niedrigeren Hürde macht. Ich hoffe, Sie schauen es sich an!
Kürzlich hat mein Team React verwendet, um mehrere ähnliche Workflows zu erstellen.
Wir finden es nützlich, die Mehrschrittformulare mit React Context zu kombinieren, damit wir uns keine Sorgen machen müssen, die gemeinsamen Zustandsdaten und Methoden als Props in jede Kind-Komponente zu übergeben.
https://reactjs.org/docs/context.html
Wow, danke für die Info, Russell! Ich habe vom Context API gehört, hatte aber noch keine Zeit, es zu erkunden. Ich werde es mir jetzt definitiv ansehen.
Toller Artikel, aber Wizard-Formulare bestehen nicht nur darin, einen Schritt vorwärts zu machen... Ich würde gerne hören, wie Sie die Fehlerbehandlung lösen würden, denn das ist die eigentliche Herausforderung. Würden Sie das Formular bei jedem Schritt oder erst am letzten Schritt absenden? Was ist, wenn Sie das Formular im letzten Schritt absenden und die serverseitige Validierung mit einer ungültigen E-Mail-Adresse antwortet, die sich im ersten Schritt befindet, wie weisen Sie den Benutzer darauf hin, diesen Schritt zu korrigieren?
Danke! :D
Das ist tatsächlich eine großartige Idee für den nächsten Beitrag! Aber die Vogelperspektive auf Ihre Fragen ist, dass die clientseitige Validierung beim Drücken der Vorwärts- und Rückwärts-Schaltfläche ausgeführt werden sollte. Das größere Problem könnte die Validierung der E-Mail sein. Ist die E-Mail bereits registriert? Wie können wir beim Server nachsehen, ob es eine doppelte E-Mail ist? Ich werde versuchen, eine Tiefenanalyse von React-Wizard-Formularen zu erstellen, in der ich dies mit einer Beispiel-App zeigen werde. Danke!
Obwohl es Spaß macht, dies mit React zu tun, würde ich argumentieren, dass es unnötig zu komplex ist.
Hier ist eine einfache Lösung, die nur HTML/CSS verwendet. Sie benötigen JS, um die nächste Schaltfläche zu deaktivieren, wenn die Eingabe ungültig ist
Hier ist ein Code, mit dem ich herumgespielt habe, um zu zeigen, dass Ihre Eingabe ungültig ist. Die Senden-Schaltfläche wird nicht gesendet, wenn ungültige Eingaben vorhanden sind. Aber wenn Sie jeden Punkt durchlaufen und die alten ausblenden, schlägt dies fehl. Sie möchten also auf jeden Fall gültige Daten für jeden Schritt haben. Und ich bin sicher, dass der Benutzer es zu schätzen wüsste, wenn er wüsste, dass das, was er eingegeben hat, vorher schlecht ist.
Es gibt ein paar Konzepte, die hier nicht erwähnt werden. Ich schätze, Sie können nicht alles abdecken, aber ich wäre daran interessiert zu sehen, wie Sie damit umgehen würden
Jeder Schritt auf seiner eigenen Route
Validierung als ein ganzes Formular, nicht nur ein Schritt. Wenn Sie zurückgehen und Werte in vorherigen Schritten ändern, kann dies die Validierung von Feldern in späteren Schritten beeinflussen
Schritte aktivieren/deaktivieren
Es gibt noch ein paar weitere, die ich hier fast erwähnt habe, aber dann feststellte, dass es irgendwie außerhalb des Rahmens dieses Artikels liegt.
Danke für die Lektüre. Seltsamerweise relevant für meine aktuelle Aufgabe.
Braucht weniger Klassen, mehr Kontext und Hooks! Ja, React hat sich wieder geändert!
Danke für deinen Artikel, Nathan!
Nur ein Tipp, um die Logik nicht zu verschleppen: Die Verantwortung für das Anzeigen/Ausblenden von Schritten wird von der Elternkomponente (in diesem Fall ) verwaltet, dann sollte es ihr obliegen zu entscheiden, welches Kind angezeigt werden soll. Im Allgemeinen ist es vorhersehbarer, ob eine Komponente im Elternteil oder in den Kindern gerendert werden soll oder nicht.
Wenn diese Logik in der Elternkomponente wäre, könnten Sie die Schritte nahtlos neu anordnen, wenn nötig. Sie wüssten nicht, welcher "Schritt" sie sind.
Ich bin sehr neugierig auf diese "get"-Funktion. Dieses Schlüsselwort habe ich noch nie gesehen und frage mich jetzt, wie das funktioniert. Google liefert nichts. Ich stimme Julio bezüglich der Rendering-Logik zu.
Während dieses Formular für einfache dreistufige Formulare gut geeignet ist, gibt es viel ähnlichen Code in jeder Kind-Komponente, und was ist, wenn Sie ein Formular mit 6 oder 10 Schritten wünschen, das mehr Logik wäre, könnte es eine Möglichkeit geben, aus diesen Komponenten zu extrahieren und sie generischer zu machen, damit sie wiederverwendet werden können? Wollte Ihre Meinung dazu wissen???