# Prop-types

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

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

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

```javascript
const App = () => {
  return (
    <React.Fragment>
      <h3>Новости</h3>
      <News/> {/* удалили передачу data */}
    </React.Fragment>
  )
}
```

Обновим страницу - видим сообщение об ошибке.

![no news error](/files/-LvLnVBoA5S6xo-84lLo)

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

Добавьте загрузку еще одного скрипта в документ:

```
<script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
```

Пусть вас не смущает версия 15.6 у пакета prop-types. Он с некоторых пор живет своей жизнью, отдельно от react.

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

```javascript
...
class News extends React.Component {
  renderNews = () => {
    ...
  }
  render() {
    ...
  }
}

// добавили propTypes. 
// propTypes (с маленькой буквы) = свойство News
News.propTypes = {
  data: PropTypes.array.isRequired // PropTypes (с большой буквы) = библиотека prop-types
}
...
```

Обновите страницу: ![data is required error](/files/-LvLnVBrvuk3sV3oEe9E)

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

Подробные "простыни" текста об ошибке - заслуга новых версий реакта. Это удобно.

Восстановим свойство data.

```javascript
const App = () => {
  return (
    <React.Fragment>
      <h3>Новости</h3>
      <News data={myNews}/>
    </React.Fragment>
  )
}
```

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

## Подробнее о propTypes

Приведу выдержку из [офф.документации](https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes):

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

    // ...

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

    // ...

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

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

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

    // ... (в документации еще есть варианты)
  }
};
```

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

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

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

```javascript
const myNews = [
  {
    id: 1,
    author: 'Саша Печкин',
    text: 'В четверг, четвертого числа...',
    bigText: 'в четыре с четвертью часа четыре чёрненьких чумазеньких чертёнка чертили чёрными чернилами чертёж.'
  },
  {
    id: 2,
    author: 'Просто Вася',
    text: 'Считаю, что $ должен стоить 35 рублей!',
    bigText: 'А евро 42!'
  },
  {
    id: 3,
    // удалили автора
    text: 'Прошло 2 года с прошлых учебников, а $ так и не стоит 35',
    bigText: 'А евро опять выше 70.'
  },
  {
    id: 4,
    author: 'Гость',
    text: 'Бесплатно. Без смс, про реакт, заходи - https://maxpfrontend.ru',
    bigText: 'Еще есть группа VK, telegram и канал на youtube! Вся инфа на сайте, не реклама!'
  }
];
```

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

![no author without prop-types](/files/-LvLnVBtdvee5qR4rXXj)

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

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

![no author without prop-types more](/files/-LvLnVBvWqJZ1PCVNUfU)

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

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

```javascript
class Article extends React.Component {
  render() {
    ...
  }
}

Article.propTypes = {
  data: PropTypes.shape({
    author: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired
  })
}
```

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

![no author with prop types error](/files/-LvLnVBxDdPBYX1nBo0w)

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

[Исходный код](https://github.com/maxfarseer/react-course-ru-v2/tree/chp6-prop-types) на данный момент.

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://max-frontend.gitbook.io/react-course-ru-v2/prop-types.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
