React. Продвинутые руководства. Часть Вторая


Продолжение серии переводов раздела "Продвинутые руководства" (Advanced Guides) официальной документации библиотеки React.js.


PropTypes — проверка типов в React


По мере того, как ваше приложение будет расти — вы можете наткнуться на большое количество ошибок, связанных с проверкой типов. Для некоторых приложений, вы можете использовать расширения JavaScript такие как Flow или TypeScript осуществляя проверку типов всего вашего приложения. Но если вы не используете таковые — React предоставляет некоторые встроенные возможности проверки типов.



Для осуществления проверки типов свойств (props) компонента, вы можете определить специальное свойство класса компонента — propTypes:


class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
  name: React.PropTypes.string
};

Модуль React.PropTypes экспортирует набор валидаторов, которые могут быть использованы для проверки получаемых данных. В этом примере мы используем валидатор React.PropTypes.string. В случае, если в свойство будет передано невалидное значение — в консоли JavaScript будет показано предупреждение. В целях производительности, propTypes проверяются только в режиме разработки (development).


React.PropTypes


В этом примере реализованы различные поддерживаемые валидаторы:


MyComponent.propTypes = {
  // Вы можете объявить, что свойство принимает один из JavaScript примитивов.
  // Обратите внимание, что обязательное наличие того или иного свойства не проверяется. 
  // Для этого есть отдельная расширенная нотация валидаторов.
  optionalArray: React.PropTypes.array,
  optionalBool: React.PropTypes.bool,
  optionalFunc: React.PropTypes.func,
  optionalNumber: React.PropTypes.number,
  optionalObject: React.PropTypes.object,
  optionalString: React.PropTypes.string,
  optionalSymbol: React.PropTypes.symbol,

  // Что-то, что React может отобразить (отрендерить): числа, строки, элементы или массив/фрагмент,
  // содержащий эти типы.
  optionalNode: React.PropTypes.node,

  // Элемент React.
  optionalElement: React.PropTypes.element,

  // Вы также можете задекларировать, что свойство является экземпляром класса. При валидации
  // используется JavaScript оператор instanceof.
  optionalMessage: React.PropTypes.instanceOf(Message),

  // Вы можете ограничить значение свойства списком значений.
  optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),

  // Ограничение свойства списком валидаторов.
  optionalUnion: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.number,
    React.PropTypes.instanceOf(Message)
  ]),

  // Ограничение, что свойство должно быть массивом значений определенного типа.
  optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),

  // Ограничение, что свойство должно быть объектом со свойствами определенного типа.
  optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),

  // Ограничение, что свойство должно быть объектом определенной формы
  // (указываются имена свойств объекта и их типы).
  optionalObjectWithShape: React.PropTypes.shape({
    color: React.PropTypes.string,
    fontSize: React.PropTypes.number
  }),

  // Здесь применяется расширенная нотация валидатора. `React.PropTypes.func` указывает на то,
  // что значение свойства должно быть функцией.
  // Нотация `.isRequired` расширяет валидатор и делает свойство обязательным.
  // `.isRequired` может использоваться с любым из поддерживаемых валидаторов.
  requiredFunc: React.PropTypes.func.isRequired,

  // Обязательное свойство любого типа
  requiredAny: React.PropTypes.any.isRequired,

  // Вы можете определить свой валидатор. Он должен возвращать объект Error если валидация не пройдена.
  // Не используйте `console.warn` или `throw`, т.к. это не будет работать в валидаторе `oneOfType`.
  customProp: function(props, propName, componentName) {
    if (!/matchme/.test(props[propName])) {
      return new Error(
        'Invalid prop `' + propName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  },

  // Вы можете использовать собственный валидатор в `arrayOf` и `objectOf`.
  // Он должен возвращать объект Error если валидация не пройдена. Валидатор
  // будет вызван для каждого ключа массива или объекта. Первые два аргумента
  // валидатора - непосредственно сам массив или объект, и ключ
  // текущего элемента.
  customArrayProp: React.PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
    if (!/matchme/.test(propValue[key])) {
      return new Error(
        'Invalid prop `' + propFullName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  })
};

Ограничение единственного потомка


С помощью React.PropTypes.element вы можете наложить ограничение, что в компонент может быть передан только один единственный потомок.


class MyComponent extends React.Component {
  render() {
    // Если в props.children будет более одного элемента возникнет предупреждение.
    const children = this.props.children;
    return (
      <div>
        {children}
      </div>
    );
  }
}

MyComponent.propTypes = {
  children: React.PropTypes.element.isRequired
};

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


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


class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

// Определение значений по умолчанию для props:
Greeting.defaultProps = {
  name: 'Stranger'
};

// Отобразит "Hello, Stranger":
ReactDOM.render(
  <Greeting />,
  document.getElementById('example')
);

В данном примере значение defaultProps будет использовано для установки значения this.props.name если оно не было определено в компоненте JSX. Проверка типов propTypes производится после установки значений из defaultProps, поэтому проверка типов также применяется в случае установки значения из defaultProps.


Следующие части:



Предыдущая часть:



Первоисточник: React — Advanced Guides — Typechecking With PropTypes

Поделиться с друзьями
-->

Комментарии (19)


  1. jMas
    12.01.2017 01:15
    +1

    static get propTypes () {
      return {
        prop: React.PropTypes.string
      };
    }

    … если использовать getter-ы, просто так красивее.


    1. gibson_dev
      12.01.2017 08:28
      +5

      Чем

      static get propTypes () {
        return {
          prop: React.PropTypes.string
        };
      }
      

      красивее?
      static propTypes {
          prop: React.PropTypes.string
      }
      


      1. eks1985
        12.01.2017 10:15
        +1

        Можно даже еще короче если импортировать PropTypes вначале


        import React, { PropTypes } from 'react';
        
        static propTypes {
            prop: PropTypes.string
        }
        


        1. bano-notit
          12.01.2017 20:00

          Тоже невалидно. Почитайте и поймёте.


          1. comerc
            12.01.2017 21:00

            Не понял, почему? Прекрасно работает.


            1. bano-notit
              12.01.2017 21:06

              Хм, странно, у меня не работает. Вы что в бабеле подключали? У меня es2015 стоит только. Может у вас какие-то stage?


              1. comerc
                12.01.2017 21:40

                Мой вопрос был в том, что дОлжно понять после прочтения про "static"?


                Настройки Babel:


                  "babel": {
                    "presets": [
                      [
                        "latest",
                        {
                          "es2015": {
                            "modules": false
                          }
                        }
                      ],
                      "react",
                      "stage-0"
                    ],


                1. bano-notit
                  12.01.2017 21:42

                  Что в es2015 статичными у классов могут быть только методы, но не свойства… Вот так вот.
                  У вас стоит stage.


                  1. comerc
                    12.01.2017 22:01

                    1. bano-notit
                      12.01.2017 22:10

                      Что-то только такой способ использования static я нашёл. Может плохо искал?


      1. staticlab
        12.01.2017 10:26

        Очевидно, ES2015-compatible.


        1. gibson_dev
          12.01.2017 10:27
          +1

          Это геттеры то? Со статическими переменными?



      1. jMas
        12.01.2017 12:45

        Ссорян, согласен — короче, красивее и читабильнее. Просто хотел сказать, что если уже ES6, то неплохо бы заюзать еще и геттеры вместо,


        MyComponent.propTypes = {
          children: React.PropTypes.element.isRequired
        };


      1. Ryotsuke
        12.01.2017 13:19

        Можно считать, что красивее в том плане, что с геттером оно явно read-only (ну, условно) и будет объявлено в теле класса, а не где-то сбоку. И на свежем ES это те же три строчки все равно:

        static get propTypes() => {
            prop: React.PropTypes.string
        }
        


        1. bano-notit
          12.01.2017 19:58
          +1

          Невалидный у вас код. Причём совсем… Стрелочные функции не имеют имён. А если уж и предположить, что имеют, то { является куском блока кода, а не литералом объекта. Надо тогда {} обернуть ещё в ().


          1. staticlab
            13.01.2017 01:01

            Для такого варианта стрелка совсем не нужна.


            1. bano-notit
              14.01.2017 11:47

              А я и не говорил, что это код примут. Но для этого варианта нужен return и ещё одни скобочки фигурные, чтобы этот код был валиден. А ещё нужно отсутствие этой дурацкой стрелки, которая там совершенно ненужна, как вы и сказали.


          1. Ryotsuke
            16.01.2017 08:39

            Да, вы правы, невалидный.
            Но это не отменяет других пунктов.