React.propTypes

ОБНОВЛЕНИЕ 2018: в учебнике хорошая теория, но ему уже два года. Проверяйте версии пакетов. За выходом нового учебника можно следить в telegram канале или twitter

На канале так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы, присоединяйтесь!

React.propTypes

(скучный, но небольшой теоретический перекур)

Перед выполнением данного урока, не забывайте, что PropTypes не работает с production версией реакта. Эта фича только для разработки, так как валидация - дорогая операция.

Давайте сломаем наш код:

var App = React.createClass({
  render: function() {
    return (
      <div className='app'>
        <h3>Новости</h3>
        <News /> {/* удалили data = {my_news} */}
      </div>
    );
  }
});

В принципе, все понятно - мы пытаемся вызвать метод map у undefined. У примитива undefined, как известно никаких методов нет - ошибка, получите распишитесь. Хорошо, что кода мало и мы быстро выяснили в чем проблема. Еще лучше, что есть возможность улучшить наше положение, добавив propTypes - специальное свойство, которое будет "валидировать" наш компонент.

Внесите изменения в компонент <News />

var News = React.createClass({
  propTypes: {
    data: React.PropTypes.array.isRequired
  },
  render: function() {
    var data = this.props.data;
    var newsTemplate;

    if (data.length > 0) {
      newsTemplate = data.map(function(item, index) {
        return (
          <div key={index}>
            <Article data={item} />
          </div>
        )
      })
    } else {
      newsTemplate = <p>К сожалению новостей нет</p>
    }

    return (
      <div className='news'>
        {newsTemplate}
        <strong className={'news__count ' + (data.length > 0 ? '':'none') }>Всего новостей: {data.length}</strong>
      </div>
    );
  }
});

Гораздо лучше! Исходя из текста ошибки нам сразу понятно куда копать: в render методе App, не указано свойство data, которое ожидается в News. Восстановим свойство data.

var App = React.createClass({
  render: function() {
    return (
      <div className='app'>
        <h3>Новости</h3>
        <News data={my_news}/>
      </div>
    );
  }
});

Вновь все работает, и наша консоль чиста.

Подробнее о propTypes

Приведу выдержку из офф.документации:

React.createClass({
  propTypes: {
    // Вы можете указать, каким примитивом должно быть свойство
    optionalArray: React.PropTypes.array,
    optionalBool: React.PropTypes.bool,
    optionalFunc: React.PropTypes.func,
    optionalNumber: React.PropTypes.number,
    optionalObject: React.PropTypes.object,
    optionalString: React.PropTypes.string,

    // Вы может указать, что свойство можеть быть одни из ...
    optionalUnion: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number,
      React.PropTypes.instanceOf(Message)
    ]),

    // Вы можете указать, конкретную структуру объекта свойства
    optionalObjectWithShape: React.PropTypes.shape({
      color: React.PropTypes.string,
      fontSize: React.PropTypes.number
    }),

    // Вы можете указать, что свойство ОБЯЗАТЕЛЬНО
    requiredFunc: React.PropTypes.func.isRequired,

    // Если нужно указать, что свойство просто обязательно, и может быть любым примитивом
    requiredAny: React.PropTypes.any.isRequired,

  }
});

Согласно этому листингу, мы можем перевести правило, указанное в компоненте <News />:

React.PropTypes.array.isRequired - свойство должно быть массивом и оно обязательно должно быть!

Я вижу по глазам некоторых (да-да, вижу), что все это какая-то бесполезная лабуда. Итак понятно - есть ошибка, есть возможность тыкнуть на нее в дебаггере и посмотреть. Специально для вас, следующая ситуация: удалите из массива my_news автора, например в третьем элементе:

var my_news = [
  {
    author: 'Саша Печкин',
    text: 'В четчерг, четвертого числа...'
  },
  {
    author: 'Просто Вася',
    text: 'Считаю, что $ должен стоить 35 рублей!'
  },
  {
    text: 'Бесплатно. Скачать. Лучший сайт - http://localhost:3000'
  }
];

Посмотрим результат:

Никаких ошибок. Но наше приложение не работает так как надо. Кто виноват? Реакт? Backend-программист который прислал нам такие данные?

Программист, может и виноват. Но реакт точно нет. У нас получилось, что в this.props.data.author содержится undefined (переменнная не определена). Поэтому react так и поступил, и показал нам "ничего" (на скриншоте это только "двоеточие").

Такую ошибку сложно отловить.

Добавьте propTypes в компонент <Article />

var Article = React.createClass({
  propTypes: {
    data: React.PropTypes.shape({
      author: React.PropTypes.string.isRequired,
      text: React.PropTypes.string.isRequired
    })
  },
  render: function() {
    var author = this.props.data.author,
        text = this.props.data.text;

    return (
      <div className='article'>
        <p className='news__author'>{author}:</p>
        <p className='news__text'>{text}</p>
      </div>
    )
  }
});

В таком случае вы получите сообщение об ошибке:

Разве это не прекрасно?

Исходный код на данный момент.

P.S. Не забудьте вернуть автора ;)

Last updated