Уловки и подсказки, чтобы вывести вашу проверку типа на новый уровень.
Для разработчиков React, которые еще не запрыгнули в поезд TypeScript, PropTypes - это образ жизни. Мы используем их ежедневно, чтобы добавить проверку типов во время выполнения к нашим компонентам React.
Но большинство из нас используют только встроенные PropTypes, такие как строка или число. Что еще мы можем сделать с PropTypes? Как они могут помочь нам создавать библиотеки и настраиваемые компоненты? Как мы можем использовать их, чтобы упразднить реквизиты и функциональность?
Давайте посмотрим на все странные и чудесные способы использования и злоупотребления PropTypes.
Начиная
Давайте посмотрим на следующий Button
компонент.
import React from 'react'; const Button = props => { return <button {...props}>{props.children}</button>; }; export default Button;
И посмотрите на это с помощью PropTypes.
import React from 'react'; import PropTypes from 'prop-types'; const Button = props => { return <button {...props}>{props.children}</button>; }; Button.propTypes = { children: PropTypes.node, }; export default Button;
Довольно захватывающий материал. Почти так же увлекательно, как и стандартный тестовый пример в create-react-app
.
Давай займемся чем-нибудь поинтереснее
import React from 'react'; import PropTypes from 'prop-types'; const Button = props => { return ( <button {...props} onClick={props.onClick} aria-disabled={props.disabled} disabled={props.disabled} > {props.children} </button> ); }; Button.propTypes = { children: PropTypes.node, disabled: PropTypes.bool, onClick: PropTypes.func.isRequired, }; export default Button;
Я добавил несколько деталей к нашей кнопке. Я добавил обязательную опору onClick
и необязательную опору disabled
.
Подождите. Должен ли onClick требоваться при любых обстоятельствах? Что делать, если Button
отключен? Если пользователь не может нажать кнопку, зачем нужен onClick
?
Знаете ли вы, что PropTypes
- это просто функции? Посмотрите, что мы можем сделать.
Button.propTypes = { children: PropTypes.node, disabled: PropTypes.bool, onClick(props, ...rest) { if (!props.disabled) { return PropTypes.func.isRequired(props, ...rest); } return PropTypes.func(props, ...rest); }, };
Прохладный! Теперь onClick
требуется только тогда, когда Button
не отключен.
Давайте пойдем еще дальше. У нас есть несколько вариантов использования ссылок, которые выглядят как кнопки. Давайте расширим наш Button
, чтобы поддержать это.
Мы добавляем опору под названием as
.
const Button = props => { const Element = props.as || 'button'; return ( <Element {...props} onClick={props.onClick} aria-disabled={props.disabled} disabled={props.disabled} > {props.children} </Element> ); }; Button.propTypes = { as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]), children: PropTypes.node, disabled: PropTypes.bool, onClick(props, ...rest) { if (!props.disabled) { return PropTypes.func.isRequired(props, ...rest); } return PropTypes.func(props, ...rest); }, };
Обратите внимание на PropType для as
.
PropTypes.oneOfType([PropTypes.string, PropTypes.elementType])
Мы можем передать строку типа a
или компонент типа Link
.
Теперь мы можем отобразить ссылку Button
вот так
<Button as="a" href="https://google.com">Google</Button>
Или даже настраиваемый элемент React. Даже react-router-link
!
import { Link } from 'react-router-dom'; <Button as={Link} to="/foo/bar">Foo</Button>
Пользовательская обработка ошибок
Теперь, когда мы поддерживаем рендеринг нашего Button
разными способами, мы можем столкнуться с некоторыми сложными ситуациями.
Как насчет этого?
<Button as="a" href="https://google.com" disabled>Google</Button>
Если вы догадались, что наш Button
не отключен - поздравляем. Вы угадали. Так как же это исправить?
Давайте определим собственный onClick
обработчик, который позаботится об этом случае.
const onClick = event => { if (props.disabled) { event.preventDefault(); return false; } if (props.onClick) { return props.onClick(event); } return false; };
Вызывая event.preventDefault
, мы запрещаем браузеру переходить по ссылке.
Но теперь, когда мы передаем onClick
функцию в отключенную Button
, мы не получаем никаких предупреждений.
Давайте снова обновим наш onClick
PropType.
onClick(props, propName, componentName, ...rest) { if (props.disabled) { throw new Error( `${componentName}: onClick has no effect when disabled is set` ); } if (!props.disabled) { return PropTypes.func.isRequired(props, ...rest); } return PropTypes.func(props, ...rest); }
Прохладный! Теперь мы получаем лучшую обратную связь, когда передаем недопустимые реквизиты.
Эти расширенные PropTypes упрощают обнаружение ошибок до того, как они попадут в рабочую среду. Их легко понять и легко использовать. До скорого!