Erstellen von Reaktionsformularen im Jahr 2020

Hallo Habr. Ich präsentiere Ihnen die Übersetzung des Artikels "Erstellen von Formularen in Reaktion im Jahr 2020" von Kristofer Selbekk

Bild


Eingabefelder Textbereiche. Optionsfelder und Kontrollkästchen. Hier sind einige der wichtigsten Interaktionspunkte, die wir als Entwickler mit unseren Benutzern haben. Wir platzieren sie auf der Website, Benutzer füllen sie aus und wenn wir Glück haben, kommen die ausgefüllten Formulare ohne Validierungsfehler zu uns.

Die Formularverarbeitung ist ein wesentlicher Bestandteil einer großen Anzahl von Webanwendungen, und dies ist eines der Dinge, die React am besten kann. Sie haben große Freiheit, Formulare zu erstellen und zu verarbeiten. Aber gibt es einen besseren Weg, dies zu tun?

Bitte beachten Sie, dass in all diesen Beispielen ein Anmeldeformular mit einem E-Mail- und Passwortfeld erstellt wird. Diese Methoden können jedoch mit den meisten Arten von Formularen verwendet werden.

Denken Sie an die Regeln guter Form


Obwohl dies nicht direkt mit dem diskutierten Thema zusammenhängt, möchte ich sicherstellen, dass Sie nicht vergessen haben, Ihre Formulare für alle verständlich zu machen. Fügen Sie Ihren Eingabefeldern Tags hinzu, legen Sie die richtigen Arienattribute für Fälle fest, in denen die Eingabe ungültig ist, und strukturieren Sie Ihren Inhalt semantisch korrekt. Dies macht es einfach, Ihr Formular sowohl für Benutzer als auch für Entwickler zu verwenden.

Verarbeiten von Formularen mit State Hook


Lassen Sie uns zunächst sehen, wie ich normalerweise mit dem Formularstatus arbeite. Ich speichere alle Felder als separate Statuselemente und aktualisiere sie alle separat. Das sieht ungefähr so ​​aus:

function LoginForm() {
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(email, password);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' value={email} onChange={(e) => setEmail(e.target.value)} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' value={password} onChange={(e) => setPassword(e.target.value)} />
      </div>
    </form>
  );
}

Zuerst erstelle ich zwei separate Teile des Status - Benutzername und Passwort. Diese beiden Variablen werden dann in das entsprechende Eingabefeld übertragen und bestimmen den Wert dieses Feldes. Wenn sich etwas in einem Feld ändert, aktualisieren wir mit Sicherheit den Statuswert, wodurch unsere Anwendung neu gezeichnet wird.

Diese Formularverarbeitung funktioniert in den meisten Fällen einwandfrei und ist einfach und leicht zu verwenden und zu verstehen. Es ist jedoch ziemlich mühsam, jedes Mal ein solches Konstrukt zu schreiben.

Erstellen eines benutzerdefinierten Hooks


Lassen Sie uns ein wenig umgestalten und unseren eigenen Hook erstellen, der unseren Code leicht verbessert:

const useFormField = (initialValue: string = '') => {
  const [value, setValue] = React.useState(initialValue);
  const onChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value), []);
  return { value, onChange };
};

export function LoginForm() {
  const emailField = useFormField();
  const passwordField = useFormField();

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(emailField.value, passwordField.value);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' {...emailField} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' {...passwordField} />
      </div>
    </form>
  );
}

Wir erstellen einen benutzerdefinierten useFormField-Hook, der einen onChange-Ereignishandler für uns erstellt und den Wert auch im Formularstatus speichert. In diesem Fall können wir unseren Hook mit allen Formularfeldern verwenden.

Verarbeitung einer großen Anzahl von Feldern


Der Nachteil dieses Ansatzes ist, dass er nicht gut skaliert werden kann, wenn Ihre Form wächst. Für kleine Formulare wie Login ist dies wahrscheinlich gut, aber wenn Sie Benutzerprofilformulare erstellen, müssen Sie möglicherweise viele Informationen anfordern! Sollen wir immer wieder unseren Haken rufen?

Immer wenn ich auf eine ähnliche Situation stoße, neige ich dazu, einen benutzerdefinierten Hook zu schreiben, der alle meine Formulare in einem großen Fragment speichert. Es könnte so aussehen:

export function LoginForm() {
  const { formFields, createChangeHandler } = useFormFields({
    email: '',
    password: '',
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(formFields.email, formFields.password);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' value={formFields.email} onChange={createChangeHandler('email')} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' value={formFields.password} onChange={createChangeHandler('password')} />
      </div>
    </form>
  );
}

Mit dem useFormFields-Hook können wir weiterhin Felder hinzufügen, ohne unsere Komponente komplexer zu gestalten. Wir können an einem Ort auf alle Formularzustände zugreifen, und unser Code sieht ordentlich und präzise aus. Natürlich müssen Sie in einigen Situationen wahrscheinlich setState verwenden, aber für die meisten Formen ist die oben beschriebene Technik in Ordnung.

Alternativer Ansatz


Daher funktioniert die Zustandsbehandlung einwandfrei, und in den meisten Fällen ist dies der bevorzugte Ansatz in React. Aber wussten Sie, dass es einen anderen Weg gibt? Es stellt sich heraus, dass der Browser standardmäßig den internen Status des Formulars verarbeitet, und wir können dies verwenden, um unseren Code zu vereinfachen!

Hier ist das gleiche Formular, aber der Browser kann den Status des Formulars verarbeiten:

export function LoginForm() {
  const handleSubmit = (e: React.FormEvent) => {
	e.preventDefault();
	const formData = new FormData(e.target as HTMLFormElement);
	api.login(formData.get('email'), formData.get('password'));
  };
  return (
	<form onSubmit={handleSubmit}>
  	<div>
    	<label htmlFor="email">Email</label>
    	<input
      	type="email"
      	id="email"
      	name="email"
    	/>
  	</div>
  	<div>
    	<label htmlFor="password">Password</label>
    	<input
      	type="password"
      	id="password"
      	name="password"
    	/>
  	</div>
  	<button>Log in</button>
	</form>
  );
}

Schau wie einfach es ist! Es wurde kein einziger Hook verwendet, es gibt keine Anfangswerteinstellung, es gibt keinen onChange-Handler. Das Beste daran ist, dass der Code immer noch wie zuvor funktioniert - aber wie?

Möglicherweise haben Sie bemerkt, dass wir in der handleSubmit-Funktion etwas anderes tun. Wir verwenden die integrierte Browser-API FormData. FormData ist eine bequeme (und gut unterstützte) Möglichkeit, Werte aus unseren Eingabefeldern abzurufen!

Wir erhalten über das Zielattribut des Submit-Ereignisses einen Link zum Formular im DOM und erstellen eine neue Instanz der FormData-Klasse. Jetzt können wir alle Felder anhand ihres Namensattributs abrufen, indem wir formData.get ("Eingabefeldname") aufrufen.

Auf diese Weise müssen Sie den Status des Formulars niemals explizit behandeln. Wenn Sie Standardwerte benötigen (z. B. wenn Sie die anfänglichen Feldwerte aus einer Datenbank oder einem lokalen Speicher ändern), bietet Ihnen React hierfür eine praktische Option defaultValue.

Wann sollte jeder Ansatz verwendet werden?


Da Formulare ein wesentlicher Bestandteil der meisten Webanwendungen sind, ist es wichtig zu wissen, wie sie behandelt werden. Und React bietet Ihnen viele Möglichkeiten, dies zu tun.
Für einfache Formulare, die keine strenge Validierung erfordern (oder die sich auf Steuerelemente zur HTML5-Formularvalidierung stützen können ), empfehle ich, einfach die integrierte Statusbehandlung zu verwenden, die das DOM uns standardmäßig zur Verfügung stellt. Es gibt einige Dinge, die Sie nicht tun können (z. B. programmgesteuertes Ändern von Eingabewerten oder eine Echtzeitprüfung), aber in den einfachsten Fällen (z. B. ein Suchfeld oder ein Anmeldefeld, wie oben angegeben) finden Sie es wahrscheinlich geeignet unser alternativer Ansatz unter Verwendung der Browser-API.

Wenn Sie eine benutzerdefinierte Prüfung durchführen oder vor dem Senden Zugriff auf einige Formulardaten benötigen, müssen Sie den Status mithilfe kontrollierter Komponenten explizit verarbeiten. Sie können reguläre useStateHooks verwenden oder einen benutzerdefinierten Hook erstellen, um Ihren Code ein wenig zu vereinfachen.

Es ist erwähnenswert, dass React-Entwickler in den meisten Fällen die Verwendung gesteuerter Komponenten empfehlen (den Status der Komponente explizit behandeln), da dieser Ansatz Ihnen in Zukunft mehr Flexibilität bietet. Meiner Meinung nach opfern Entwickler häufig die Einfachheit aus Gründen der Flexibilität, die sie häufig nicht benötigen.

Unabhängig davon, für welchen Ansatz Sie sich entscheiden, war die Verarbeitung von React-Formularen noch nie so einfach wie heute. Sie können den Browser einfache Formulare verarbeiten lassen und gleichzeitig den Status der Formulare explizit verarbeiten, wenn die Situation dies erfordert. Ich hoffe, dass die oben genannten Methoden nützlich sind und Ihnen helfen, das Problem zu lösen, indem Sie die Anzahl der Zeilen in Ihrem Code reduzieren.

All Articles