Tworzenie własnej biblioteki walidacji React: doświadczenie programisty (część 3)

Opublikowany: 2022-03-10
Krótkie podsumowanie ↬ Widzieliśmy już, jak możemy zaimplementować podstawowe części naszej biblioteki walidacji i jak dodać wszystkie potrzebne funkcje, które warto mieć. Ta ostatnia część tej serii skupi się na poprawie doświadczenia użytkownika dla osób, które będą korzystać z naszej biblioteki walidacji: programistów.

Jeśli śledziłeś tę małą serię artykułów, nauczyłeś się teraz, jak stworzyć własną bibliotekę walidacji. Poradzi sobie z prawie każdym wyzwaniem, jakie możesz mu rzucić, a nawet pomaga w kwestiach dostępności! Jedynym minusem jest to, że praca z nim jest do bani.

Tak, zgadza się. Doświadczenia użytkownika z punktu widzenia programisty poważnie brakuje. Nie otrzymujemy żadnych pomocnych ostrzeżeń, gdy błędnie piszemy słowa, niewłaściwie używamy interfejsów API lub, cóż, cokolwiek, naprawdę!

W tym artykule dowiesz się, w jaki sposób możesz ulepszyć środowisko programistyczne swojej biblioteki walidacyjnej — lub dowolnej biblioteki w tym celu.

  • Część 1: Podstawy
  • Część 2: Funkcje
  • Część 3: Doświadczenie

Zaczyna się

Od ostatniej części tego artykułu wyciągnęliśmy cały kod biblioteki do jego własnych plików. Spójrz na demo CodeSandbox, aby zobaczyć, od czego zaczynamy.

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Wygodne funkcje

Chcemy, aby nasza biblioteka była jak najprostsza w użyciu w najczęstszych przypadkach. Sposobem na osiągnięcie tego celu jest dodanie wygodnych funkcji narzędziowych dla określonej funkcjonalności.

Jedną z takich funkcji może być sprawdzenie, czy nasz formularz jest prawidłowy — to znaczy, czy wszystkie komunikaty o błędach są null . Jest to coś, co zwykle sprawdzasz w module obsługi onSubmit , ale może być również przydatne w metodzie renderowania. Zaimplementujmy to!

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

Umieścimy tę flagę w naszym module obsługi formularza onSubmit , a także w naszej metodzie renderowania.

  • Zobacz demo CodeSandbox

Jest ich o wiele więcej, które można by napisać, ale niech to będzie ćwiczenie dla czytelnika.

Ostrzeżenia dotyczące rozwoju i niezmienniki

Jedną z największych zalet Reacta jest wiele pomocnych ostrzeżeń konsoli podczas programowania. Powinniśmy zapewnić ten sam rodzaj jakości również naszym użytkownikom.

Na początek stworzymy dwie funkcje — warning o logowaniu ostrzeżeń do konsoli i invariant w przypadku zgłaszania błędu — obie, jeśli dany warunek nie jest spełniony.

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

Chcesz użyć invariant , jeśli błąd spowoduje awarię twojej biblioteki (lub sprawi, że będzie bezużyteczna) i warning o złych praktykach lub inne porady.

Kiedy ostrzegać?

Decyzja, kiedy ostrzec, jest bardzo ważna. Za dużo i jesteś po prostu denerwujący. Za mało, a krytyczne błędy trafiają do produkcji. Dlatego musimy być mądrzy w naszych ostrzeżeniach.

Ponieważ nasza biblioteka akceptuje dość duży obiekt konfiguracyjny, warto to jakoś sprawdzić — przynajmniej podczas programowania. Moglibyśmy to rozwiązać za pomocą systemu typów, takiego jak TypeScript lub Flow, ale to wyklucza wszystkich zwykłych użytkowników JavaScript.

Zamiast tego utwórzmy narzędzie do sprawdzania schematu środowiska wykonawczego, w którym sprawdzamy, czy konfiguracja zawiera prawidłowe pola i wyświetlamy odpowiednie ostrzeżenia.

 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 }

Prawdopodobnie moglibyśmy to robić jeszcze przez jakiś czas, gdybyśmy chcieli spędzić czas. I powinieneś! To świetny sposób na ulepszenie środowiska programistycznego Twojej aplikacji.

Nie musisz jednak pisać tego ręcznie. Istnieje port przeglądarki popularnej biblioteki joi do walidacji schematów obiektowych, który może pomóc w tworzeniu naprawdę przyjemnego sprawdzania walidacji w czasie wykonywania. Ponadto, jak wspomniano wcześniej, system typów pomógłby wyłapać błędy konfiguracji w czasie kompilacji dla użytkowników korzystających z tego systemu typów.

Pozwól na elastyczność

Dobre wrażenia programistyczne w dużej mierze nie przeszkadzają programistom. Przyjrzyjmy się kilku sposobom, w jakie możemy ulepszyć to doświadczenie.

Skomponuj sprzeczne rekwizyty

Po pierwsze, nasi pobierający rekwizyty stosują pewne rekwizyty do naszych danych wejściowych i formularzy, które mogą zostać przypadkowo nadpisane przez naszych konsumentów. Zamiast tego dodajmy obiekt zastępujący właściwości do naszych getterów właściwości, które połączą ze sobą wszystkie sprzeczne właściwości.

Oto jak możemy to zaimplementować w naszym 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] || '', }),

Podobne podejście można zastosować w getFormProps .

Pomóż uniknąć wiercenia podpór

Niektóre formularze mogą być duże i podzielone na kilka elementów. Zamiast spuszczać rekwizyty wiertnicze naszych konsumentów z drzewa, powinniśmy podać kontekst. W ten sposób mogą uzyskać dostęp do wszystkich rzeczy, które zwracamy z naszego niestandardowego haka, gdziekolwiek w poniższym drzewie.

Najpierw utwórzmy ValidationContext za pomocą metody createContext w React:

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

Następnie utwórzmy komponent ValidationProvider , który zamiast tego dostarcza wszystkie wartości z haka useValidation w kontekście:

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

Teraz, zamiast bezpośrednio wywoływać useValidation , zapakowalibyśmy nasz formularz w komponent ValidationProvider i uzyskalibyśmy dostęp do właściwości walidacji ( getFormProps , errors itp.) za pomocą haka useContext . Używałbyś go w ten sposób:

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

W ten sposób uzyskasz to, co najlepsze z obu światów! Dostajesz prosty zaczep do tych prostych scenariuszy i uzyskujesz elastyczność, której potrzebujesz do tych złożonych części.

Dokumentacja jest kluczowa

Zawsze, gdy korzystam z biblioteki, której sam nie napisałem, uwielbiam świetną dokumentację. Ale na czym powinieneś się skupić i gdzie powinieneś dokumentować?

Pierwszym krokiem powinno być zebranie prostego i zrozumiałego pliku README z dostępnymi najbardziej podstawowymi przykładami użycia. Andrew Healey napisał niesamowity artykuł o tym, jak napisać dobre README, które gorąco polecam.

Kiedy stworzysz dobre README, aby zachęcić ludzi do działania, dobrym pomysłem może być witryna z dokumentacją. Tutaj możesz umieścić bardziej dogłębną dokumentację API, przepisy na typowe przypadki użycia i stare dobre FAQ.

Istnieją świetne narzędzia do generowania stron z dokumentacją. Moim ulubionym jest docusaurus z Facebooka (skromna przechwałka: użyliśmy go podczas tworzenia strony internetowej create-react-app ), ale istnieje kilka dobrych alternatyw.

W tym artykule nie będziemy omawiać, jak napisać dobrą dokumentację. Istnieje kilka dobrych artykułów — nawet społeczność o nazwie „Write the Docs”. Napisali świetny przewodnik, jak zacząć pisać świetną dokumentację.

Streszczenie

W tej serii artykułów stworzyliśmy całkiem przyzwoitą bibliotekę walidacji. Ma dość prosty interfejs API, elastyczność w razie potrzeby, dobre wrażenia dla programistów i wiele ciekawych funkcji.

Prześledziliśmy krok po kroku, jak wdrażaliśmy różne rzeczy i mam nadzieję, że lepiej rozumiesz, jak możesz stworzyć własną bibliotekę i jak zrobić z niej coś, z czego ludzie chcieliby korzystać.

Daj mi znać w komentarzach, co myślisz i czy były jakieś części, na których utknąłeś lub miałeś trudności ze zrozumieniem. Zrobię co w mojej mocy, aby zaktualizować artykuł, gdy pojawią się opinie.

Na zakończenie tego artykułu — oto ostateczna wersja:

  • Zobacz demo CodeSandbox

Dziękuje za przeczytanie!