Erstellen Ihrer eigenen React-Validierungsbibliothek: Die Entwicklererfahrung (Teil 3)

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Wir haben also bereits gesehen, wie wir die grundlegenden Teile unserer Validierungsbibliothek implementieren können und wie wir alle nützlichen Funktionen hinzufügen können, die wir benötigen. Dieser letzte Teil dieser Serie konzentriert sich auf die Verbesserung der Benutzererfahrung für die Personen, die unsere Validierungsbibliothek verwenden: die Entwickler.

Wenn Sie diese kleine Artikelserie verfolgt haben, haben Sie jetzt gelernt, wie Sie Ihre eigene Validierungsbibliothek zusammenstellen können. Es kann fast jede Herausforderung bewältigen, die Sie ihm stellen können, und es hilft sogar bei Bedenken hinsichtlich der Barrierefreiheit! Der einzige Nachteil ist, dass es scheiße ist, damit zu arbeiten.

Ja, das stimmt. Die Benutzererfahrung aus Entwicklersicht ist ernsthaft mangelhaft. Wir erhalten keine hilfreichen Warnungen, wenn wir Wörter falsch schreiben, APIs missbrauchen oder, nun ja, wirklich alles!

Dieser Artikel führt Sie durch, wie Sie die Entwicklererfahrung Ihrer Validierungsbibliothek verbessern können – oder aus diesem Grund jede Bibliothek.

  • Teil 1: Die Grundlagen
  • Teil 2: Die Funktionen
  • Teil 3: Die Erfahrung

Ausgehen

Seit dem letzten Teil dieses Artikels haben wir den gesamten Bibliothekscode in seine eigenen Dateien gezogen. Werfen Sie einen Blick auf die CodeSandbox-Demo, um zu sehen, womit wir beginnen.

Mehr nach dem Sprung! Lesen Sie unten weiter ↓

Komfortfunktionen

Wir möchten, dass unsere Bibliothek für die häufigsten Fälle so einfach wie möglich zu verwenden ist. Eine Möglichkeit, sich diesem Ziel zu nähern, besteht darin, für bestimmte Funktionen praktische Hilfsfunktionen hinzuzufügen.

Eine solche Funktion könnte darin bestehen, zu überprüfen, ob unser Formular gültig ist – das heißt, ob alle Fehlermeldungen null sind. Dies ist etwas, das Sie normalerweise in Ihrem onSubmit Handler überprüfen, aber es könnte auch in Ihrer Render-Methode nützlich sein. Setzen wir es um!

 const isFormValid = useMemo( () => Object.values(errors).every(error => error === null), [errors] );

Wir stellen dieses Flag in unserem onSubmit Formular-Handler sowie in unserer Render-Methode bereit.

  • Siehe CodeSandbox-Demo

Es gibt noch viel mehr davon, die geschrieben werden könnten, aber ich lasse das eine Übung für den Leser sein.

Entwicklungswarnungen und Invarianten

Eines der größten Features von React sind die vielen hilfreichen Konsolenwarnungen während der Entwicklung. Die gleiche Qualität sollten wir auch unseren Nutzern bieten.

Zu Beginn erstellen wir zwei Funktionen – warning zum Protokollieren von Warnungen in der Konsole und invariant zum Auslösen eines Fehlers – beide, wenn eine bestimmte Bedingung nicht erfüllt ist.

 function warning(condition, message) { if (process.env.NODE_ENV === 'production' || condition) { return; } console.warn('useValidation: ' + message); } function invariant(condition, message) { if (process.env.NODE_ENV === 'production' || condition) { return; } throw new Error('useValidation: ' + message); }

Sie möchten invariant verwenden, wenn der Fehler Ihre Bibliothek zum Absturz bringt (oder sie unbrauchbar macht), und vor schlechten Praktiken oder anderen Ratschlägen warning .

Wann warnen?

Die Entscheidung, wann gewarnt werden soll, ist ziemlich wichtig. Zu viele, und du nervst nur noch. Zu wenige, und Sie lassen kritische Fehler an die Produktion liefern. Daher müssen wir mit unseren Warnungen klug umgehen.

Da unsere Bibliothek ein ziemlich großes Konfigurationsobjekt akzeptiert, ist es sinnvoll, dies irgendwie zu validieren – zumindest während der Entwicklung. Wir könnten es lösen, indem wir ein Typsystem wie TypeScript oder Flow verwenden, aber das schließt alle normalen alten JavaScript-Benutzer aus.

Lassen Sie uns stattdessen einen Runtime-Schema-Checker erstellen, bei dem wir überprüfen, ob die Konfiguration die richtigen Felder enthält, und relevante Warnungen ausgeben.

 function validateConfigSchema(config) { if (process.env.NODE_ENV === 'production') { return; } if (typeof config === 'function') { config = config({}); } invariant( typeof config === 'object', `useValidation should be called with an object or a function returning an object. You passed a ${typeof config}.`, ); invariant( typeof config.fields === 'object', 'useValidation requires a `field` prop with an object containing the fields and their validators. Please refer to the documentation on usage: https://link.to/docs' ); invariant( Object.values(config.fields).every(field => typeof field === 'object'), 'useValidation requires that the `field` object only contains objects. It looks like yours isn\'t. Please refer to the documentation on usage: https://link.to/docs' ); warning( ['always', 'blur', 'submit', undefined].includes(config.showError), 'useValidation received an unsupported value in the `showError` prop. Valid values are "always", "blur" or "submit".' ) // And so on }

Wir könnten wahrscheinlich noch eine Weile so weitermachen, wenn wir die Zeit verbringen wollten. Und das sollten Sie! Dies ist eine großartige Möglichkeit, das Entwicklererlebnis Ihrer App zu verbessern.

Sie müssen diese jedoch nicht von Hand schreiben. Es gibt eine Browser-Portierung der beliebten Objekt-Schema-Validierungsbibliothek joi , die bei der Erstellung einer wirklich netten Laufzeit-Validierungsprüfung helfen könnte. Außerdem würde, wie bereits erwähnt, ein Typsystem dazu beitragen, Konfigurationsfehler zur Kompilierzeit für die Benutzer abzufangen, die dieses Typsystem verwenden.

Flexibilität zulassen

Eine gute Entwicklererfahrung steht den Entwicklern größtenteils nicht im Weg. Sehen wir uns einige Möglichkeiten an, wie wir diese Erfahrung verbessern können.

Komponieren Sie widersprüchliche Requisiten

Erstens wenden unsere Prop-Getter einige Props auf unsere Eingaben und Formulare an, die von unseren Verbrauchern versehentlich überschrieben werden können. Stattdessen fügen wir unseren Prop-Gettern ein Prop-Override-Objekt hinzu, das alle widersprüchlichen Props zusammensetzt.

So können wir dies in unseren getFieldProps :

 getFieldProps: (fieldName, overrides = {}) => ({ onChange: e => { const { value } = e.target; if (!config.fields[fieldName]) { return; } dispatch({ type: 'change', payload: { [fieldName]: value }, }); if (overrides.onChange) { overrides.onChange(e); } }, onBlur: e => { dispatch({ type: 'blur', payload: fieldName }); if (overrides.onBlur) { overrides.onBlur(e) } }, name: overrides.name || fieldName, value: state.values[fieldName] || '', }),

Ein ähnlicher Ansatz kann in getFormProps .

Helfen Sie Prop Drilling zu vermeiden

Einige Formulare können groß sein und in mehrere Komponenten aufgeteilt werden. Anstatt die Bohrstützen unserer Verbraucher den Baum herunterfallen zu lassen, sollten wir einen Kontext bereitstellen. Auf diese Weise können sie auf alle Dinge zugreifen, die wir von unserem benutzerdefinierten Hook irgendwo im Baum unten zurückgeben.

Lassen Sie uns zunächst einen ValidationContext mit der Methode createContext von React erstellen:

 export const ValidationContext = React.createContext({});

Als Nächstes erstellen wir eine Komponente ValidationProvider , die stattdessen alle Werte aus dem useValidation im Kontext bereitstellt:

 export const ValidationProvider = props => { const context = useValidation(props.config); return ( {props.children} ); }; export const ValidationProvider = props => { const context = useValidation(props.config); return ( {props.children} ); }; export const ValidationProvider = props => { const context = useValidation(props.config); return ( {props.children} ); };

Anstatt useValidation direkt aufzurufen, würden wir jetzt unser Formular in eine ValidationProvider -Komponente einschließen und mithilfe des useContext Hooks Zugriff auf die Validierungsprops ( getFormProps , errors usw.) erhalten. Sie würden es so verwenden:

 Import React, { useContext } from 'react'; import { ValidationContext } from './useValidation'; function UsernameForm(props) { const { getFieldProps, errors } = useContext(ValidationContext); return ( <> <input {...getFieldProps('username')} /> {errors.username && {errors.username}></span>} </> ); }

Auf diese Weise erhalten Sie das Beste aus beiden Welten! Sie erhalten einen einfachen Haken für diese einfachen Szenarien und die Flexibilität, die Sie für diese komplexen Teile benötigen.

Dokumentation ist der Schlüssel

Immer wenn ich eine Bibliothek verwende, die ich nicht selbst geschrieben habe, liebe ich großartige Dokumentation. Aber worauf sollten Sie sich konzentrieren und wo sollten Sie dokumentieren?

Ein erster Schritt sollte darin bestehen, eine leicht verständliche README-Datei zusammenzustellen, in der die grundlegendsten Anwendungsbeispiele leicht verfügbar sind. Andrew Healey hat einen erstaunlichen Artikel darüber geschrieben, wie man eine gute README-Datei schreibt, die ich Ihnen wärmstens zum Lesen empfehle.

Wenn Sie eine gute README erstellt haben, um die Leute zum Laufen zu bringen, könnte eine Dokumentations-Website eine gute Idee sein. Hier können Sie eine ausführlichere API-Dokumentation, Rezepte für typische Anwendungsfälle und eine gute alte FAQ einstellen.

Es gibt großartige Tools zum Erstellen von Dokumentations-Websites. Mein Favorit ist docusaurus von Facebook (bescheidene Prahlerei: Wir haben es beim Erstellen der Website „Create create-react-app “ verwendet), aber es gibt mehrere gute Alternativen.

Wir werden in diesem Artikel nicht darauf eingehen, wie man eine gute Dokumentation schreibt. Es gibt mehrere gute Artikel da draußen – sogar eine Community namens „Write the Docs“. Sie haben einen großartigen Leitfaden geschrieben, wie Sie mit dem Schreiben großartiger Dokumentation beginnen können.

Zusammenfassung

Durch diese Artikelserie haben wir eine ziemlich anständige Validierungsbibliothek erstellt. Es hat eine ziemlich einfache API, Flexibilität, wenn Sie es brauchen, eine gute Entwicklererfahrung und viele ziemlich geile Funktionen.

Wir sind Schritt für Schritt durchgegangen, wie wir die Dinge implementiert haben, und ich hoffe, Sie haben ein tieferes Verständnis dafür bekommen, wie Sie Ihre eigene Bibliothek erstellen können und wie Sie sie zu etwas machen, das die Leute gerne verwenden würden.

Bitte lassen Sie mich in den Kommentaren wissen, was Sie denken, und wenn es einige Teile gab, bei denen Sie hängen geblieben sind oder Schwierigkeiten hatten, sie zu verstehen. Ich werde mein Bestes tun, um den Artikel zu aktualisieren, sobald Feedback eintrifft.

Um diesen Artikel zu beenden – hier ist die endgültige Version:

  • Siehe CodeSandbox-Demo

Danke fürs Lesen!