Проверка типов с помощью PropTypes
Примечание:
С версии React 15.5
React.PropTypes
были вынесены в отдельный пакет. Так что используйте библиотекуprop-types
.Вы можете использовать codemod-скрипт, чтобы провести замену в коде на использование этой библиотеки.
По мере роста вашего приложения вы можете отловить много ошибок с помощью проверки типов. Для этого можно использовать расширения JavaScript вроде Flow и TypeScript. Но, даже если вы ими не пользуетесь, React предоставляет встроенные возможности для проверки типов. Для запуска этой проверки на пропсах компонента вам нужно использовать специальное свойство propTypes
:
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Привет, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
В данном примере проверка типа показана на классовом компоненте, но она же может быть применена и к функциональным компонентам, или к компонентам, созданным с помощью React.memo
или React.forwardRef
.
PropTypes
предоставляет ряд валидаторов, которые могут использоваться для проверки, что получаемые данные корректны. В примере мы использовали PropTypes.string
. Когда какой-то проп имеет некорректное значение, в консоли будет выведено предупреждение. По соображениям производительности propTypes
проверяются только в режиме разработки.
PropTypes
Пример использования возможных валидаторов:
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// Можно объявить проп на соответствие определённому JS-типу.
// По умолчанию это не обязательно.
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// Все, что может быть отрендерено:
// числа, строки, элементы или массивы
// (или фрагменты) содержащие эти типы
optionalNode: PropTypes.node,
// React-элемент
optionalElement: PropTypes.element,
// Тип React-элемент (например, MyComponent).
optionalElementType: PropTypes.elementType,
// Можно указать, что проп должен быть экземпляром класса
// Для этого используется JS-оператор instanceof.
optionalMessage: PropTypes.instanceOf(Message),
// Вы можете задать ограничение конкретными значениями
// при помощи перечисления
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// Объект, одного из нескольких типов
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// Массив объектов конкретного типа
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// Объект со свойствами конкретного типа
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// Объект с определённой структурой
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// При наличии необъявленных свойств в объекте будут вызваны предупреждения
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// Можно добавить`isRequired` к любому приведённому выше типу,
// чтобы показывать предупреждение,
// если проп не передан
requiredFunc: PropTypes.func.isRequired,
// Обязательное значение любого типа
requiredAny: PropTypes.any.isRequired,
// Можно добавить собственный валидатор.
// Он должен возвращать объект `Error` при ошибке валидации.
// Не используйте `console.warn` или `throw`
// - это не будет работать внутри `oneOfType`
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Проп `' + propName + '` компонента' +
' `' + componentName + '` имеет неправильное значение'
);
}
},
// Можно задать свой валидатор для `arrayOf` и `objectOf`.
// Он должен возвращать объект Error при ошибке валидации.
// Валидатор будет вызван для каждого элемента в массиве
// или для каждого свойства объекта.
// Первые два параметра валидатора
// - это массив или объект и ключ текущего элемента
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Проп `' + propFullName + '` компонента' +
' `' + componentName + '` имеет неправильное значение'
);
}
})
};
Требование одного дочернего элемента
С помощью PropTypes.element
вы можете указать, что только один дочерний элемент может быть передан компоненту в качестве потомка.
import PropTypes from 'prop-types';
class MyComponent extends React.Component {
render() {
// Это должен быть ровно один элемент, иначе вы увидите предупреждение.
const children = this.props.children;
return (
<div>
{children}
</div>
);
}
}
MyComponent.propTypes = {
children: PropTypes.element.isRequired
};
Значения пропсов по умолчанию
Вы можете задать значения по умолчанию для ваших props
с помощью специального свойства defaultProps
:
class Greeting extends React.Component {
render() {
return (
<h1>Привет, {this.props.name}</h1>
);
}
}
// Задание значений по умолчанию для пропсов:
Greeting.defaultProps = {
name: 'Незнакомец'
};
// Отрендерит "Привет, Незнакомец":
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);
Если вы используете один из Babel-плагинов по преобразованию кода, вроде plugin-proposal-class-properties (прежнее название — plugin-transform-class-properties), то можете объявить defaultProps
как статическое свойство класса (для компонента-наследника от React.Component
). Этот синтаксис ещё не утверждён, так что для его работы в браузере нужна компиляция. Подробнее смотрите в предложении о полях класса.
class Greeting extends React.Component {
static defaultProps = {
name: 'незнакомец'
}
render() {
return (
<div>Привет, {this.props.name}</div>
)
}
}
Определение defaultProps
гарантирует, что this.props.name
будет иметь значение, даже если оно не было указано родительским компонентом. Сначала применяются значения по умолчанию, заданные в defaultProps
. После запускается проверка типов с помощью propTypes
. Так что проверка типов распространяется и на значения по умолчанию.
Функциональные компоненты
К функциональным компонентам можно также применять PropTypes.
Допустим, есть такой компонент:
export default function HelloWorldComponent({ name }) {
return (
<div>Hello, {name}</div>
)
}
Для добавления PropTypes нужно объявить компонент в отдельной функции, которую затем экспортировать:
function HelloWorldComponent({ name }) {
return (
<div>Hello, {name}</div>
)
}
export default HelloWorldComponent
А затем добавить PropTypes напрямую к компоненту HelloWorldComponent
:
import PropTypes from 'prop-types'
function HelloWorldComponent({ name }) {
return (
<div>Hello, {name}</div>
)
}
HelloWorldComponent.propTypes = {
name: PropTypes.string
}
export default HelloWorldComponent