Table of Contents
Так как 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