Prop Types

Так как JavaScript это динамически типизированный язык, то у нас нет реальной возможности указывать тип переменной во время компилирования и если мы передадим неверные типы, они поломают наше приложение во время работы или выдадут странные результаты, если эти типы совместимы, но не являются тем, чего мы ожидаем.

Для этого можно использовать расширения JavaScript вроде Flow и TypeScript. Или использовать встроенные возможности для проверки типов React. Для запуска этой проверки на пропсах компонента вам нужно использовать специальное свойство propTypes:

Functional Component

import PropTypes from "prop-types";
const Greeting = (props) => {
return <h1>Hello, {props.name}</h1>;
};
Greeting.propTypes = {
name: PropTypes.string,
};

Class Components

import PropTypes from "prop-types";
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Greeting.propTypes = {
name: PropTypes.string,
};

Установка

npm install --save prop-types

Зачем это нужно? 🤔

  • Объявление типов происходит настолько явно, насколько это возможно, поиск ошибки не занимает много времени.
  • Централизация типов помогает избегать самоповторов.

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,
// Можно указать, что проп должен быть экземпляром класса
// Для этого используется оператор `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(
"Prop `" +
propFullName +
"` component" +
" `" +
componentName +
"` getting wrong value"
);
}
}),
};

Централизация PropTypes

Централизовать типы можно (и даже нужно) в отдельном фале в своей отдельной папке. Классический пример для описания обьекта:

import { shape, number, string, oneOf } from 'prop-types';
export const userType = shape({
id: number,
firstName: string.isRequired,
lastName: string.isRequired,
company: string,
role: oneOf(['user', 'author']),
address: shape({
id: number.isRequired,
street: string.isRequired,
street2: string,
city: string.isRequired,
state: string.isRequired,
postal: number.isRequired
});
});

Дальнейшее использование:

import React from 'react';
import {userType} from './types';
const User = ¬({ user }) => {
return (
<div>
<h1>{user.firstName} {user.lastName}</h1>
</div>
)
}
User.propTypes = {
user: userType.isRequired
};
export default User;

Преимущества этого подхода:

  • Централизованные типы существенно упрощают их объявление в компоненте.
  • Централизованные типы просто объявляют форму, их можно отмечать как обязательные.
  • Нет необходимости в копипасте. Если форма объекта меняется позже, внести изменения нужно только в одном месте.

Значения пропсов по умолчанию

Вы можете задать значения по умолчанию для ваших props с помощью специального свойства defaultProps:

Functional Component

const Greeting = (props) => {
return <h1>Hello, {props.name}</h1>;
};
Greeting.defaultProps = {
name: "John",
};

Class Component

import PropTypes from "prop-types";
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Greeting.defaultProps = {
name: "John",
};
Default Props

Определение defaultProps гарантирует, что this.props.name будет иметь значение, даже если оно не было указано родительским компонентом. Сначала применяются значения по умолчанию, заданные в defaultProps. После запускается проверка типов с помощью propTypes. Так что проверка типов распространяется и на значения по умолчанию.

Практика 👩‍💻👨‍💻

Пользуясь практикой, В задание UserList добавить propTypes к всем компонентам где это возможно

Edit this page on GitHub