Créer votre propre bibliothèque de validation React : l'expérience du développeur (partie 3)
Publié: 2022-03-10Si vous avez suivi cette petite série d'articles, vous avez maintenant appris à créer votre propre bibliothèque de validation. Il peut relever presque tous les défis que vous pouvez lui lancer, et il aide même à résoudre les problèmes d'accessibilité ! Son seul inconvénient est qu'il est nul de travailler avec.
Oui, c'est vrai. L'expérience utilisateur du point de vue du développeur fait sérieusement défaut. Nous ne recevons aucun avertissement utile lorsque nous mal orthographions des mots, abusons des API ou, eh bien, quoi que ce soit, vraiment !
Cet article vous guidera à travers la façon dont vous pouvez améliorer l'expérience de développement de votre bibliothèque de validation - ou de toute bibliothèque à cet effet.
- Partie 1 : Les bases
- Partie 2 : Les fonctionnalités
- Partie 3 : L'expérience
Commençant
Depuis la dernière partie de cet article, nous avons extrait tout le code de la bibliothèque dans ses propres fichiers. Jetez un œil à la démo CodeSandbox pour voir par quoi nous commençons.
Fonctions de confort
Nous voulons que notre bibliothèque soit aussi simple que possible à utiliser pour les cas les plus courants. Une façon d'atteindre cet objectif consiste à ajouter des fonctions utilitaires pratiques pour certaines fonctionnalités.
Une de ces fonctionnalités pourrait être de vérifier si notre formulaire est valide, c'est-à-dire si tous les messages d'erreur sont null
. C'est quelque chose que vous vérifiez généralement dans votre gestionnaire onSubmit
, mais cela pourrait également être utile dans votre méthode de rendu. Mettons-le en œuvre !
const isFormValid = useMemo( () => Object.values(errors).every(error => error === null), [errors] );
Nous fournirons cet indicateur dans notre gestionnaire de formulaire onSubmit
, ainsi que dans notre méthode de rendu.
- Voir la démo CodeSandbox
Il y en a beaucoup d'autres qui pourraient être écrites, mais je vais laisser cela être un exercice pour le lecteur.
Avertissements de développement et invariants
L'une des plus grandes fonctionnalités de React est ses nombreux avertissements de console utiles lors du développement. Nous devons également fournir le même type de qualité à nos utilisateurs.
Pour commencer, nous allons créer deux fonctions - warning
pour consigner les avertissements dans la console et invariant
pour générer une erreur - les deux si une condition donnée n'est pas remplie.
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); }
Vous souhaitez utiliser invariant
si l'erreur va planter votre bibliothèque (ou la rendre inutile), et warning
des mauvaises pratiques ou d'autres conseils.
Quand avertir
Décider quand avertir est assez important. Trop, et vous êtes juste ennuyeux. Trop peu, et vous laissez les bogues critiques être envoyés en production. Par conséquent, nous devons être intelligents avec nos avertissements.
Étant donné que notre bibliothèque accepte un objet de configuration assez volumineux, il est logique de le valider d'une manière ou d'une autre, du moins lors du développement. Nous pourrions le résoudre en utilisant un système de type comme TypeScript ou Flow, mais cela exclut tous les utilisateurs réguliers de JavaScript.
Au lieu de cela, créons un vérificateur de schéma d'exécution, où nous validons que la configuration contient les champs corrects et affichons les avertissements pertinents.
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 }
Nous pourrions probablement continuer à faire cela pendant un certain temps si nous voulions passer le temps. Et vous devriez ! C'est un excellent moyen d'améliorer l'expérience de développement de votre application.
Cependant, vous n'êtes pas obligé de les écrire à la main. Il existe un port de navigateur de la bibliothèque de validation de schéma d'objet populaire joi
qui pourrait aider à créer une très belle vérification de validation d'exécution. De plus, comme mentionné précédemment, un système de type aiderait à détecter les erreurs de configuration au moment de la compilation pour les utilisateurs qui utilisent ce système de type.
Autoriser la flexibilité
Une bonne expérience de développeur consiste en grande partie à ne pas gêner les développeurs. Examinons quelques façons d'améliorer cette expérience.
Composer des accessoires contradictoires
Tout d'abord, nos prop getters appliquent certains props à nos entrées et formulaires qui peuvent être accidentellement remplacés par nos consommateurs. Au lieu de cela, ajoutons un objet prop override à nos access getters, qui composeront ensemble tous les accessoires en conflit.
Voici comment nous pouvons implémenter cela dans notre 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] || '', }),
Une approche similaire peut être suivie dans getFormProps
.
Aide à éviter le forage d'accessoires
Certains formulaires peuvent être volumineux et divisés en plusieurs composants. Au lieu de faire des accessoires de forage de nos consommateurs dans l'arbre, nous devrions fournir un contexte. De cette façon, ils peuvent accéder à tous les éléments que nous renvoyons à partir de notre crochet personnalisé n'importe où dans l'arborescence ci-dessous.
Commençons par créer un ValidationContext avec la méthode createContext
de React :
export const ValidationContext = React.createContext({});
Ensuite, créons un composant ValidationProvider
, qui fournit à la place toutes les valeurs du crochet useValidation
en contexte :
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} ); };
Maintenant, au lieu d'appeler useValidation
directement, nous envelopperions notre formulaire dans un composant ValidationProvider
et nous aurions accès aux accessoires de validation ( getFormProps
, errors
, etc.) en utilisant le crochet useContext
. Vous l'utiliseriez comme ceci :
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>} </> ); }
De cette façon, vous obtenez le meilleur des deux mondes ! Vous obtenez un crochet simple pour ces scénarios simples, et vous obtenez la flexibilité dont vous avez besoin pour ces pièces complexes.
La documentation est la clé
Chaque fois que j'utilise une bibliothèque que je n'ai pas écrite moi-même, j'aime la bonne documentation. Mais sur quoi devez-vous vous concentrer et où devez-vous documenter ?
Une première étape devrait être de créer un fichier README simple à comprendre, avec les exemples d'utilisation les plus élémentaires facilement disponibles. Andrew Healey a écrit un article étonnant sur la façon d'écrire un bon README, que je vous recommande fortement de lire.
Lorsque vous avez créé un bon README pour faire avancer les gens, un site Web de documentation peut être une bonne idée. Ici, vous pouvez mettre une documentation API plus détaillée, des recettes pour des cas d'utilisation typiques et une bonne vieille FAQ.
Il existe d'excellents outils pour générer des sites Web de documentation. Mon préféré est docusaurus
de Facebook (humble vantard : nous l'avons utilisé lors de la création du site Web create-react-app
), mais il existe plusieurs bonnes alternatives.
Nous n'allons pas expliquer comment rédiger une bonne documentation dans cet article. Il existe plusieurs bons articles, même une communauté appelée "Write the Docs". Ils ont écrit un excellent guide sur la façon dont vous pouvez commencer à écrire une excellente documentation.
Sommaire
Grâce à cette série d'articles, nous avons créé une bibliothèque de validation assez décente. Il a une API assez simple, une flexibilité lorsque vous en avez besoin, une bonne expérience de développeur et de nombreuses fonctionnalités intéressantes.
Nous avons expliqué comment nous avons implémenté les choses étape par étape, et j'espère que vous avez mieux compris comment créer votre propre bibliothèque et comment en faire quelque chose que les gens aimeraient utiliser.
S'il vous plaît laissez-moi savoir dans les commentaires ce que vous pensez, et s'il y a des parties sur lesquelles vous êtes bloqué ou avez eu du mal à comprendre. Je ferai de mon mieux pour mettre à jour l'article au fur et à mesure que les commentaires arriveront.
Pour terminer cet article, voici la version finale :
- Voir la démo CodeSandbox
Merci d'avoir lu!