Создание собственной библиотеки проверки React: опыт разработчика (часть 3)
Опубликовано: 2022-03-10Если вы следили за этой небольшой серией статей, вы теперь узнали, как собрать свою собственную библиотеку проверки. Он может справиться практически с любой задачей, которую вы можете ему бросить, и даже помогает с проблемами доступности! Единственный его недостаток в том, что с ним неудобно работать.
Да, верно. Пользовательский опыт с точки зрения разработчика серьезно отсутствует. Мы не получаем никаких полезных предупреждений, когда мы неправильно пишем слова, неправильно используем API или вообще что-то еще!
В этой статье вы узнаете, как улучшить взаимодействие разработчиков с вашей библиотекой проверки — или любой другой библиотекой для этого.
- Часть 1: Основы
- Часть 2: Особенности
- Часть 3: Опыт
Начинающийся
Начиная с последней части этой статьи, мы вытащили весь код библиотеки в отдельные файлы. Взгляните на демо-версию CodeSandbox, чтобы увидеть, с чего мы начинаем.
Удобные функции
Мы хотим, чтобы наша библиотека была максимально простой в использовании для наиболее распространенных случаев. Способ двигаться к этой цели — добавить удобные служебные функции для определенных функций.
Одной из таких функций может быть проверка правильности нашей формы, то есть, все ли сообщения об ошибках имеют null
. Это то, что вы обычно проверяете в своем обработчике onSubmit
, но это может быть полезно и в вашем методе рендеринга. Давайте реализуем это!
const isFormValid = useMemo( () => Object.values(errors).every(error => error === null), [errors] );
Мы предоставим этот флаг в нашем обработчике формы onSubmit
, а также в нашем методе рендеринга.
- См. демонстрацию CodeSandbox
Их можно было бы написать еще много, но пусть это будет упражнением для читателя.
Предупреждения и инварианты разработки
Одной из замечательных особенностей React является множество полезных предупреждений консоли во время разработки. Мы должны предоставить такое же качество и нашим пользователям.
Для начала мы создадим две функции — warning
для записи предупреждений в консоль и invariant
для выдачи ошибки — обе, если заданное условие не выполняется.
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); }
Вы хотите использовать invariant
, если ошибка приведет к сбою вашей библиотеки (или сделает ее бесполезной), а также warning
о плохих практиках или другие советы.
Когда предупреждать
Очень важно решить, когда предупреждать. Слишком много, и ты просто раздражаешь. Слишком мало, и вы позволяете критическим ошибкам отправляться в производство. Поэтому нам нужно быть умными с нашими предупреждениями.
Поскольку наша библиотека принимает довольно большой объект конфигурации, имеет смысл как-то проверить это — хотя бы в процессе разработки. Мы могли бы решить эту проблему, используя систему типов, такую как TypeScript или Flow, но это исключает всех обычных пользователей старого JavaScript.
Вместо этого давайте создадим средство проверки схемы во время выполнения, в котором мы проверяем, содержит ли конфигурация правильные поля, и выводим соответствующие предупреждения.
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 }
Возможно, мы могли бы продолжать делать это какое-то время, если бы хотели провести время. И вы должны! Это отличный способ улучшить опыт разработчиков вашего приложения.
Однако вам не обязательно писать их вручную. Существует браузерный порт популярной библиотеки проверки схемы объектов joi
, которая может помочь в создании действительно хорошей проверки проверки во время выполнения. Кроме того, как упоминалось ранее, система типов поможет отловить ошибки конфигурации во время компиляции для пользователей, использующих эту систему типов.
Разрешить гибкость
Хороший опыт разработчиков в значительной степени не мешает разработчикам. Давайте рассмотрим несколько способов улучшить этот опыт.
Составьте конфликтующие реквизиты
Во-первых, наши получатели свойств применяют некоторые свойства к нашим входам и формам, которые могут быть случайно переопределены нашими потребителями. Вместо этого давайте добавим объект переопределения свойств в наши геттеры свойств, которые будут объединять любые конфликтующие свойства вместе.
Вот как мы можем реализовать это в нашем 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] || '', }),
Аналогичный подход можно использовать в getFormProps
.
Помогите избежать сверления с опорой
Некоторые формы могут быть большими и разделенными на несколько компонентов. Вместо того, чтобы заставлять наших потребителей сверлить реквизиты по дереву, мы должны предоставить контекст. Таким образом, они могут получить доступ ко всем материалам, которые мы возвращаем из нашего пользовательского хука, в любом месте дерева ниже.
Во-первых, давайте создадим ValidationContext с помощью метода React createContext
:
export const ValidationContext = React.createContext({});
Затем давайте создадим компонент ValidationProvider
, который вместо этого предоставляет все значения из хука useValidation
в контексте:
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} ); };
Теперь, вместо прямого вызова useValidation
, мы обернем нашу форму в компонент ValidationProvider
и получим доступ к параметрам проверки ( getFormProps
, errors
и т. д.) с помощью хука useContext
. Вы бы использовали это так:
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>} </> ); }
Таким образом, вы получаете лучшее из обоих миров! Вы получаете простой хук для этих простых сценариев, и вы получаете гибкость, необходимую для этих сложных частей.
Документация — это ключ
Всякий раз, когда я использую библиотеку, которую написал не сам, мне нравится отличная документация. Но на чем вам следует сосредоточиться и где вы должны документировать?
Первым шагом должно быть составление простого для понимания файла README с наиболее простыми примерами использования. Эндрю Хили написал замечательную статью о том, как написать хороший README, которую я настоятельно рекомендую вам прочитать.
Когда вы создали хороший README, чтобы заставить людей работать, веб-сайт документации может быть хорошей идеей. Здесь вы можете разместить более подробную документацию по API, рецепты для типичных случаев использования и старый добрый FAQ.
Существуют отличные инструменты для создания веб-сайтов с документацией. Мой фаворит — docusaurus
от Facebook (скромное хвастовство: мы использовали его при создании веб-сайта create-react-app
), но есть несколько хороших альтернатив.
В этой статье мы не будем подробно рассказывать, как писать хорошую документацию. Есть несколько хороших статей — даже сообщество под названием «Write the Docs». Они написали отличное руководство о том, как начать писать отличную документацию.
Резюме
В этой серии статей мы создали довольно приличную библиотеку проверки. У него довольно простой API, гибкость, когда вам это нужно, хороший опыт разработчика и множество довольно сырых функций.
Мы шаг за шагом рассмотрели, как мы реализовывали вещи, и я надеюсь, что вы получили более глубокое понимание того, как вы можете создать свою собственную библиотеку и как сделать ее такой, чтобы люди хотели ее использовать.
Пожалуйста, дайте мне знать в комментариях, что вы думаете, и были ли какие-то части, на которых вы застряли или с трудом поняли. Я постараюсь обновлять статью по мере поступления отзывов.
Чтобы закончить эту статью — вот окончательный вариант:
- См. демонстрацию CodeSandbox
Спасибо за прочтение!