Перевірка типів за допомогою PropTypes

Примітка:

React.PropTypes переміщено в інший пакет починаючи з React версії 15.5. Будь-ласка надалі замість нього використовуйте бібліотеку 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. Якщо якийсь проп отримає невірне значення, в консолі JavaScript буде показано попередження. З міркувань продуктивності 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
  }),
  
  // An object with warnings on extra properties
  optionalObjectWithStrictShape: PropTypes.exact({
    name: PropTypes.string,
    quantity: PropTypes.number
  }),   

  // Ви можете додати `isRequired` після будь-якого з наведених вище типів.
  // В цьому випадку буде показано попередження, якщо проп не надано.
  requiredFunc: PropTypes.func.isRequired,

  // Значення будь-якого типу
  requiredAny: PropTypes.any.isRequired,

  // Ви також можете вказати власну функцію-валідатор. Вона повинна повернути об'єкт
  // Error, якщо валідація не пройшла. Не викликайте `console.warn` і не генеруйте виняткову
  // ситуацію, так як це не працюватиме всередині конструкції `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
};

Значення пропсів за замовчуванням

Ви можете задати значення за замовчуванням для ваших пропсів присвоївши спеціальну властивість defaultProps:

class Greeting extends React.Component {
  render() {
    return (
      <h1>Привіт, {this.props.name}</h1>
    );
  }
}

// Задає значення пропсів за замовчуванням:
Greeting.defaultProps = {
  name: 'Незнайомець'
};

// Рендерить "Привіт, Незнайомець":
ReactDOM.render(
  <Greeting />,
  document.getElementById('example')
);

Якщо ви використовуєте Babel-плагін для трансформації коду transform-class-properties, то ви можете задати defaultProps як статичну властивість класу React-компонента. Цей синтаксис ще поки не затверджено і він буде потребувати кроку компіляції для того, щоб ваш компонент працював у браузері. Щоб дізнатись більше, дивіться пропозицію про поля класу.

class Greeting extends React.Component {
  static defaultProps = {
    name: 'Незнайомець'
  }

  render() {
    return (
      <div>Привіт, {this.props.name}</div>
    )
  }
}

Властивість defaultProps гарантує, що this.props.name матиме значення, навіть якщо воно не було задане батьківським компонентом. Перевірка типів propTypes відбувається після застосування defaultProps, тобто вона також буде застосована для defaultProps.