Der richtige Einsatz von Formularen mit React
Motivation
In der heutigen Zeit zeichnet sich vermehrt ein Trend zur Entwicklung von Webanwendungen in der Cloud ab, welcher den Einsatz von nativen Entwicklungen stark reduziert. Dies hat zu einer wachsenden Community und einer Reihe von Open Source Frameworks im Netz geführt, welche ein großes Angebot an neuen Technologien und Ideen bereitstellen. Entscheider, Architekten und Entwickler stehen damit immer wieder vor neuen Herausforderungen und Überlegungen, welche neuen Frameworks und Bibliotheken im nächsten Softwareprojekt Verwendung finden. Es gilt abzuwägen, ob eine Lösung noch zeitgemäß für ein neues Projekt ist oder ob sie noch zu neu ist (Stichwort “Bleeding Edge”) und damit potenziell instabil ist oder sich zukünftig auf dem Markt nicht durchsetzen wird. Gerade im Bereich JavaScript ist es schwer einen Überblick zu behalten, da fast wöchentlich neue Frameworks und Bibliotheken erscheinen.
Im nachfolgenden Artikel wird speziell der Umgang mit Formularen in einer Webanwendung diskutiert, da diese in nahezu jeder Applikation Anwendung finden. Formulare bieten einen einfachen Weg mit dem Nutzer zu interagiert und Informationen abzufragen. Betrachtet man hier zudem das Thema der Validierung dieser Daten, können selbst Formulare mit einer kleinen Anzahl an Feldern schnell komplex werden. Die Erfahrung zeigt, dass sich im Laufe eines Entwicklungsprozesses Anforderungen stetig ändern und somit auch kontinuierliche Anpassungen am Quellcode notwendig werden. Bei komplexen Formularen steigen hier der Entwicklungs- und Wartungsaufwand schnell. Um eine Einführung zu diesem Thema zu geben stützen wir uns auf das Framework React.
React ist durch die Arbeit an Facebook entstanden und wurde als Open Source Projekt der Community zur Verfügung gestellt. Durch die Entwicklungserfahrung aus mehreren Softwareprojekten hat sich im Umgang mit React gezeigt, dass die Nutzung von Formularen flexibel aber auch effizient umsetzbar ist. Dieser Artikel gibt hierzu einen ersten Einblick anhand eines einfachen Beispiels und diskutiert drei unterschiedliche Lösungsansätze.
Anforderungen an eine Lösung
1. Wiederverwendbarkeit: Aktuelle Webframeworks arbeiten komponentenbasiert. Einzelne Elemente auf einer Webseite können in Komponenten ausgelagert werden. Dadurch kann der Quellcode einer Webanwendung sauber strukturiert werden und es kann Duplizierung von Code vermieden werden. Existiert beispielsweise ein Formular zur Erfassung einer Postanschrift (Name, Straße, Ort), so soll es möglich sein dieses zu einem späteren Zeitpunkt an einer anderen Stelle wieder zu verwenden, ohne den Quellcode duplizieren zu müssen.
2. Wartbarkeit: Muss eine Änderung an einem Formular vorgenommen werden, so sollte dies möglichst nur an einer Stelle im Code nötig sein und die entsprechende Stelle sollte leicht aufzufinden sein.
3. Validierung: Eingaben von Benutzern müssen besonders betrachtet werden. Es muss möglich sein, Anforderungen an Eingaben einfach zu definieren. Hierzu zählen Prüfung auf Pflichtfelder, minimale bzw. maximale Länge von Eingaben, Prüfung auf valide Emailadressen, Postleitzahlen oder Ähnliches.
4. Standardisierung: Eine fokussierte Lösung sollte eine möglichst große Community haben, welche folgenden Vorteile mit sich bringt: Große Anzahl verfügbarer Entwickler, schnelle Fehlerbehebung und guter Support bei Problemen.
Die Umsetzung
Wir betrachten anhand eines einfachen Beispiels drei mögliche Wege dieses mit React umzusetzen. Das Formular selbst enthält drei Felder:
· Name: Das Feld soll ein Pflichtfeld sein und der eingegebene Name soll mindestens drei Zeichen lang sein
· Alter: Das Feld soll ein Pflichtfeld sein und das eingegebene Alter soll zwischen 18 und 65 liegen
· Email: Das Feld soll ein Pflichtfeld sein und bei der Eingabe soll es sich um eine valide Emailadresse handeln
Die erste Implementierung (Anhang 1) die wir betrachten wollen kommt ohne zusätzliche Bibliotheken aus und verwendet ausschließlich Sprachelemente von React. Die Werte der Felder werden im Zustand der Komponente abgespeichert und über den Konstruktor initial gesetzt. Diese werden in der render() Methode über das value Attribut an die jeweiligen Input Elemente übergeben. Eine Veränderung eines Input Elements durch den Benutzer ruft die onChange() Methode auf, welche eine Zustandsänderung der Komponente bewirkt. Im Anschluss wird eine Validierung des entsprechenden Feldes durchgeführt. Beim Blick auf die Implementierung fällt auf, dass die Validierungslogik einen Großteil der ganzen Komponente einnimmt. Würde man diese in eine eigene Klasse/Funktionen auslagern wäre sie ebenfalls einfach wieder verwendbar und auch einfach wartbar. Die Menge an Boiler Plate Code ist allerdings für ein kleines Formular mit nur drei Feldern ziemlich hoch.
Eine deutliche Verbesserung der Lesbarkeit und auch eine geringe Reduzierung des Boiler Plate Codes bietet die zweite Implementierung (Anhang 2). Durch die Einführung von Hooks in React 16.8 lassen sich React Komponenten, welche eigene Zustandsvariablen verwenden, nicht mehr ausschließlich als Klasse schreiben. Dies führt zu deutlich lesbarerem und einfach verständlicherem Quellcode. Was das Formular betrifft, verwenden wir den Hook useState um den Zustand der Felder abzubilden. Durch den Hook useEffect kann eine Zustandsveränderung erkannt werden und automatisch die Validierung durchgeführt werden. Im Vergleich zum ersten Ansatz ist die Validierungslogik dadurch sehr viel verständlicher.
Die dritte und letzte Implementierung (Anhang 3) verwendet die Bibliotheken Formik (zur Vereinfachung des Formulars) und Yup (zur Validierung der Benutzereingaben). Formik erlaubt es den Boiler Plate Code noch einmal deutlich zu reduzieren. Die Zustandshaltung und -veränderung aus den vorherigen Implementierungen wird nicht mehr benötigt. Zusätzlich bietet Formik noch eine Fülle an weiteren Features, die aber nicht Bestandteil dieses Artikels sind. Die Validierung ist durch die intuitive Syntax von Yup leicht zu verstehen und gut wartbar.
Fazit
Vergleicht man die erste Implementierung bei der ausschließlich React verwendet wurde, mit der dritten Implementierung mit Formik, wurden ca. 46 Zeilen Code eingespart, was grob 38% entspricht. Einzelne Bestandteile oder ganze Formulare sind einfach wiederzuverwenden durch den Komponentenbasierten Aufbau von React. Der Wartungsaufwand ist ebenfalls gering, da bei richtiger Anwendung kein duplizierter Code entsteht und einzelne Komponenten sehr übersichtlich sind da fast keinen Boiler Plate Code notwendig ist. Die Validierungslogik lässt sich durch den Einsatz einer externen Bibliothek sehr stark vereinfachen. Durch die weite Verbreitung von React handelt es sich ebenfalls um eine Lösung welche ausreichend getestet und robust ist und man läuft nicht in Gefahr in kurzer Zeit Legacy Code zu entwickeln. Denkt man an ein Szenario in einem Enterprise Umfeld, bei dem größere Formulare entwickelt werden und der Aufbau der Formulare sich dynamisch verändert, fallen die hier beschriebenen Vorteile noch sehr viel deutlicher ins Gewicht. Zum Zeitpunkt der Erstellung dieses Artikels ist Formik eine der Bibliotheken mit der höchsten Entwicklungsaktivität und der höchsten Bewertung auf Github. Im Gegensatz zu anderen Bibliotheken (z.B. Redux Form) verwendet Formik ausschließlich React Sprachelemente und kommt größtenteils ohne externe Bibliotheken aus.
Zusammengefasst bietet der Einsatz einer Bibliothek wie Formik bereits bei kleinen Formularen einen Mehrwert. Je größer und umfangreicher Formulare werden ist der Einsatz einer Bibliothek sogar sehr zu empfehlen.
Anhang
1. Implementierung als Class Component
Quellcode ebenfalls zu finden unter https://stackblitz.com/edit/react-vg31bw?embed=1&file=AsReactClass.js
2. Implementierung als Functional Component
Quellcode ebenfalls zu finden unter https://stackblitz.com/edit/react-vg31bw?embed=1&file=AsReactFunction.js
3. Implementierung mit Formik
Quellcode ebenfalls zu finden unter https://stackblitz.com/edit/react-vg31bw?file=AsFormik.js