Crearea propriei biblioteci de validare React: experiența dezvoltatorului (partea 3)

Publicat: 2022-03-10
Rezumat rapid ↬ Așadar, am văzut deja cum putem implementa părțile de bază ale bibliotecii noastre de validare și cum să adăugăm toate caracteristicile plăcute de care aveam nevoie. Această parte finală a acestei serii se va concentra pe îmbunătățirea experienței utilizatorului pentru persoanele care vor folosi biblioteca noastră de validare: dezvoltatorii.

Dacă ați urmărit această mică serie de articole, acum ați învățat cum să vă creați propria bibliotecă de validare. Poate face față aproape oricărei provocări pe care o poți arunca și chiar ajută cu problemele de accesibilitate! Singurul său dezavantaj este că e nasol să lucrezi cu el.

Da, așa este. Experiența utilizatorului din punct de vedere al dezvoltatorului lipsește serios. Nu primim avertismente utile atunci când scriem greșit cuvinte, folosim greșit API-urile sau, ei bine, orice, cu adevărat!

Acest articol vă va ghida prin modul în care puteți îmbunătăți experiența de dezvoltator a bibliotecii dvs. de validare - sau a oricărei biblioteci de aceea.

  • Partea 1: Bazele
  • Partea 2: Caracteristicile
  • Partea 3: Experiența

Început

De la ultima parte a acestui articol, am extras tot codul bibliotecii în propriile fișiere. Aruncă o privire la demonstrația CodeSandbox pentru a vedea cu ce începem.

Mai multe după săritură! Continuați să citiți mai jos ↓

Funcții de confort

Ne dorim ca biblioteca noastră să fie cât mai simplă de utilizat pentru cele mai comune cazuri. O modalitate de a ajunge la acest obiectiv este adăugarea de funcții utilitare convenabile pentru anumite funcționalități.

O astfel de caracteristică ar putea fi să verificăm dacă formularul nostru este valid, adică dacă toate mesajele de eroare sunt null . Acesta este ceva pe care îl verificați de obicei în handlerul dvs. onSubmit , dar ar putea fi util și în metoda dvs. de redare. Să-l punem în aplicare!

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

Vom furniza acest semnal în gestionarea formularului onSubmit , precum și în metoda noastră de randare.

  • Vedeți demonstrația CodeSandbox

Mai sunt multe dintre acestea care ar putea fi scrise, dar voi lăsa să fie un exercițiu pentru cititor.

Avertismente de dezvoltare și invarianți

Una dintre cele mai mari caracteristici ale React este numeroasele sale avertismente utile pe consolă în timpul dezvoltării. Ar trebui să oferim același tip de calitate și utilizatorilor noștri.

Pentru a începe, vom crea două funcții - warning pentru înregistrarea avertismentelor în consolă și invariant pentru a arunca o eroare - ambele dacă o anumită condiție nu este îndeplinită.

 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); }

Doriți să utilizați invariant dacă eroarea vă va prăbuși biblioteca (sau o va face inutilă) și warning pentru practici proaste sau alte sfaturi.

Când să avertizez

Este destul de important să decideți când să avertizați. Prea multe și ești doar enervant. Prea puține și lăsați erorile critice să fie livrate în producție. Prin urmare, trebuie să fim inteligenți cu avertismentele noastre.

Deoarece biblioteca noastră acceptă un obiect de configurare destul de mare, este logic să validăm acest lucru cumva - cel puțin în timpul dezvoltării. L-am putea rezolva folosind un sistem de tipuri precum TypeScript sau Flow, dar care exclude toți utilizatorii JavaScript vechi.

În schimb, să creăm un verificator de schemă de rulare, în care validăm că configurația conține câmpurile corecte și imprimăm avertismente relevante.

 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 }

Probabil că am putea continua să facem asta pentru o vreme dacă am vrea să petrecem timpul. Și ar trebui! Este o modalitate excelentă de a îmbunătăți experiența de dezvoltator a aplicației dvs.

Cu toate acestea, nu trebuie să le scrieți de mână. Există un port de browser al bibliotecii de validare a schemei de obiecte populare joi , care ar putea ajuta la crearea unei verificări de validare a runtimei cu adevărat plăcute. De asemenea, după cum sa menționat anterior, un sistem de tip ar ajuta la identificarea erorilor de configurare în timpul compilării pentru utilizatorii care folosesc acel sistem de tip.

Permite flexibilitate

O experiență bună de dezvoltator nu le împiedică în mare parte în calea dezvoltatorilor. Să ne uităm la câteva moduri în care putem îmbunătăți această experiență.

Compune elemente de recuzită conflictuale

În primul rând, utilizatorii noștri de recuzită aplică unele elemente de recuzită intrărilor și formularelor noastre care pot fi înlocuite accidental de consumatorii noștri. În schimb, haideți să adăugăm un obiect de suprascriere prop la elementele noastre de colectare a prop, care vor compune împreună orice elemente de recuzită conflictuale.

Iată cum putem implementa acest lucru în 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] || '', }),

O abordare similară poate fi urmată în getFormProps .

Ajutați la evitarea forajului cu prop

Unele forme pot fi mari și împărțite în mai multe componente. În loc să punem suportul de foraj al consumatorilor noștri în josul copacului, ar trebui să oferim un context. În acest fel, ei pot accesa toate lucrurile pe care le returnăm din cârligul nostru personalizat oriunde în arborele de mai jos.

Mai întâi, să creăm un ValidationContext cu metoda createContext a lui React:

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

În continuare, să creăm o componentă ValidationProvider , care furnizează în schimb toate valorile din cârligul useValidation în context:

 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} ); };

Acum, în loc să apelăm direct useValidation , ne-am împacheta formularul într-o componentă ValidationProvider și am avea acces la elementele de recuzită de validare ( getFormProps , errors etc) prin utilizarea cârligului useContext . L-ai folosi astfel:

 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>} </> ); }

În acest fel, obții tot ce este mai bun din ambele lumi! Obțineți un cârlig simplu pentru acele scenarii simple și obțineți flexibilitatea de care aveți nevoie pentru acele părți complexe.

Documentația este cheia

Ori de câte ori folosesc o bibliotecă pe care nu am scris-o eu, îmi place documentarea grozavă. Dar pe ce ar trebui să te concentrezi și unde ar trebui să te documentezi?

Un prim pas ar trebui să fie crearea unui README simplu de înțeles, cu cele mai simple exemple de utilizare disponibile. Andrew Healey a scris un articol uimitor despre cum să scrieți un README bun, pe care vi-l recomand cu căldură să îl citiți.

Când ați creat un README bun pentru a stimula oamenii, un site web de documentare ar putea fi o idee bună. Aici, puteți pune o documentație API mai aprofundată, rețete pentru cazuri tipice de utilizare și o întrebare veche.

Există instrumente grozave pentru a genera site-uri web de documentare. Preferatul meu este docusaurus de la Facebook (laudă umilă: l-am folosit când am creat site-ul web create-react-app ), dar există câteva alternative bune.

Nu vom analiza cum să scriem o documentație bună în acest articol. Există mai multe articole bune acolo - chiar și o comunitate numită „Scrie documentele”. Ei au scris un ghid excelent despre cum puteți începe să scrieți documentație grozavă.

rezumat

Prin această serie de articole, am creat o bibliotecă de validare destul de decentă. Are un API destul de simplu, flexibilitate pentru atunci când aveți nevoie, o experiență bună de dezvoltator și o mulțime de funcții destul de ușoare.

Am analizat modul în care am implementat lucrurile pas cu pas și sper că ați înțeles mai profund cum vă puteți crea propria bibliotecă și cum o faceți ceva ce oamenii ar dori să o folosească.

Vă rog să-mi spuneți în comentarii ce părere aveți și dacă au fost unele părți în care v-ați blocat sau v-ați înțeles greu. Voi încerca tot posibilul să actualizez articolul pe măsură ce apare feedback.

Pentru a încheia acest articol, iată versiunea finală:

  • Vedeți demonstrația CodeSandbox

Multumesc pentru lectura!