# Использование props

У каждого компонента могут быть свойства. Они хранятся в `this.props`, и передаются компоненту как атрибуты.

**Общий вид:**

```javascript
const wizard = {name: Garry, surname: Potter};
<MyComponent data={wizard} eshe_odno_svoistvo={[1,2,3,4,5]} />
```

В свойство можно передать любой javascript примитив, объект, переменную и даже выражение. Значение свойства должно быть взято в фигурные скобки.

Значения доступны через `this.props.ИМЯ_СВОЙСТВА` (в statefull-компонентах) или в первом аргументе функции (в stateless).

В нашем случае, если говорить про statefull, мы получим:

* _this.props.data_ - объект `{name: Garry, surname: Potter}`
* _this.props.eshe\_odno\_svoistvo_ - массив `[1,2,3,4,5]`

this.props используются **только** для чтения!

Давайте создадим несколько новостей для нашего приложения.

Добавьте в начало script-тэга массив с данными

```javascript
const myNews = [
  {
    author: 'Саша Печкин',
    text: 'В четверг, четвертого числа...'
  },
  {
    author: 'Просто Вася',
    text: 'Считаю, что $ должен стоить 35 рублей!'
  },
  {
    author: 'Max Frontend',
    text: 'Прошло 2 года с прошлых учебников, а $ так и не стоит 35'
  },
  {
    author: 'Гость',
    text: 'Бесплатно. Без смс, про реакт, заходи - https://maxpfrontend.ru'
  }
];
```

И измените строку с подключением компонента News следующим образом:

_index.html_

```jsx
...
const myNews = [
  {
    author: 'Саша Печкин',
    text: 'В четверг, четвертого числа...'
  },
  {
    author: 'Просто Вася',
    text: 'Считаю, что $ должен стоить 35 рублей!'
  },
  {
    author: 'Max Frontend',
    text: 'Прошло 2 года с прошлых учебников, а $ так и не стоит 35'
  },
  {
    author: 'Гость',
    text: 'Бесплатно. Без смс, про реакт, заходи - https://maxpfrontend.ru'
  }
];

const News = () => {
  return <p>К сожалению, новостей нет</p>
}

const Comments = () => {
  return <p>Нет новостей - комментировать нечего.</p>
}

const App = () => {
  return (
    <React.Fragment>
      <News data={myNews}/> {/* добавили свойство data */}
      <Comments />
    </React.Fragment>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
...
```

Обратите внимание, комментарии внутри JSX пишутся в фигурных скобках: `{/* текст комментария */}`

Так же прошу заметить, что JSX это не весь js-код, который содержится в тэге script, грубо говоря JSX - это HTML-разметка + переменные/выражения. Поэтому в остальных местах можно писать комментарии привычным для вас способом ( //... или /\*...\*/ )

Откройте в консоли вкладку react (конечно, предварительно обновив страницу).

![свойства компонента News](https://2647972981-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvLmy8qHKus4tjYXHI4%2F-LvLmyreyxcNGjR6qn1l%2F-LvLnXmL2K6rzuLM2gHt%2Fnews-props.jpg?generation=1575561867875472\&alt=media)

**Напомню**: в данный момент, мы добавили свойство _data_ в наш компонент `<News />`. Необязательно было называть свойство так, можно было написать, например:

```javascript
<News posledine_novosti={my_news} />
```

Тогда в консоли разработчика, это выглядело бы так:

![last news](https://2647972981-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvLmy8qHKus4tjYXHI4%2F-LvLmyreyxcNGjR6qn1l%2F-LvLnXmNTntQBZosNeq2%2Fnews-props-poslednie-novosti.jpg?generation=1575561867931348\&alt=media)

Ок, у нашего компонента есть свойство, в котором лежат наши новости, но компонент не умеет их отображать. Это легко исправить.

Представим HTML разметку для наших новостей:

```markup
<div class="news">
  <p class="news__author">Саша Печкин:</p>
  <p class="news__text">В четверг, четвертого числа...</p>
</div>
```

**Вопрос:** У нас есть разметка для одного элемента данных, есть данные целиком (массив myNews). Как отобразить эти данные?

**Ответ:** Нужно создать шаблон, пройтись по всем переменным в массиве с новостями и подставить значения.

Когда вам нужно отобразить переменную в шаблоне разметки JSX - она так же оборачивается в фигурные скобки. На практике это выглядит проще, чем в теории, поэтому давайте представим, как может выглядеть наша JSX разметка:

```javascript
this.props.data.map(function(item, index) {
  return (
    <div key={index}>
      <p className="news__author">{item.author}:</p>
      <p className="news__text">{item.text}</p>
    </div>
  )
})
```

1. Мы использовали метод массивов - _Map_. Если вы незнакомы с ним, [прочитайте документацию](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
2. Мы обернули разметку внутри _return_ в корневой элемент `<div>`. Мы могли бы обернуть ее в любой другой элемент, главное, **напоминаю** - внутри _return_ всегда должен возвращаться DOM-узел (то есть, что угодно, обернутое в родительский тэг или в React.Fragment).
3. Мы использовали у родительского элемента атрибут **key** (`<div key={index}>`). Если объяснить предельно просто: реакту нужна уникальность, чтобы все его механизмы работали корректно. По "ключу" _он_ будет понимать с каким именно дочерним узлом вы работаете и какому родителю он принадлежит. Индекс - не идеальный вариант для ключа, мы это исправим далее.
4. Мы использовали в шаблоне, значения переменных + текст, например `<p className="news__author">{item.author}:</p>` которое могло бы быть представлено в нативном js-коде как `<p className="news__author">''+item.author+':'</p>` (пустая строка + значение переменной + двоеточие)

В результате работы функции map, мы получили новый массив, состоящий из необходимых нам реакт-элементов. Это и есть решение нашей задачи, нам осталось лишь сохранить этот массив в переменной, например `newsTemplate`, и в _render_ функции компонента `<News />` вернуть разметку + "переменную-шаблон".

News по-быстрому переделаем в statefull (через class ... extends):

_index.html_

```javascript
...
const myNews = [
  {
    author: 'Саша Печкин',
    text: 'В четверг, четвертого числа...'
  },
  {
    author: 'Просто Вася',
    text: 'Считаю, что $ должен стоить 35 рублей!'
  },
  {
    author: 'Max Frontend',
    text: 'Прошло 2 года с прошлых учебников, а $ так и не стоит 35'
  },
  {
    author: 'Гость',
    text: 'Бесплатно. Без смс, про реакт, заходи - https://maxpfrontend.ru'
  }
];

class News extends React.Component {
  render() {
    const newsTemplate = this.props.data.map(function(item, index) {
      return (
        <div key={index}>
          <p className="news__author">{item.author}:</p>
          <p className="news__text">{item.text}</p>
        </div>
      )
    })

    console.log(newsTemplate)

    return (
      <div className="news">
        {newsTemplate}
      </div>
    )
  }
}
...
```

Посмотрим что получилось: ![новости отображены](https://2647972981-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvLmy8qHKus4tjYXHI4%2F-LvLmyreyxcNGjR6qn1l%2F-LvLnXmPsdUChge_QcNA%2FnewsTemplate-item-author-text.jpg?generation=1575561867919438\&alt=media)

Вы еще не в восторге? Количество кода - кот наплакал.

Напоследок, мне не хочется, но придется вновь разрушить магию. Давайте посмотрим, что возвращает `console.log(newsTemplate)` (откройте вкладку Console).

Взглянем в консоль: ![no magic news screen](https://2647972981-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvLmy8qHKus4tjYXHI4%2F-LvLmyreyxcNGjR6qn1l%2F-LvLnXmRpqqZySLgYM95%2FnewsTemplate.jpg?generation=1575561867942969\&alt=media)

Объект, у объекта свойства... все как обычно в мире javascript.

## Почему не стоит указывать index в качестве ключа

Если кому интересны причины, то приведу вам комментарий из старого учебника:

> P.S. Здесь и в продолжении всего курса в коде для отображения массива новостей используется `key = {index}`. Обратите внимание на следующую ветку [комментариев](https://habrahabr.ru/post/279249/#comment_8807873) (спасибо _DeLaVega_ и _geakstr_).

Суть в том, что index не лучший вариант для ключа, когда ваши "айтемы" могут менять порядок. У нас новости не меняются, но тем не менее, мы можем быстро решить нашу проблему добавив "действительно" уникальное значение, которое не будет изменяться, если у элементов поменяется index.

Конечно же, это свойство называется id ;) Добавим его в массив и будем использовать в качестве ключа.

_index.html_

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

class News extends React.Component {
  render() {
    const newsTemplate = this.props.data.map(function(item) {
      return (
        <div key={item.id}> {/* используем id в качестве ключа */}
          <p className="news__author">{item.author}:</p>
          <p className="news__text">{item.text}</p>
        </div>
      )
    })

    return (
      <div className="news">
        {newsTemplate}
      </div>
    )
  }
}
...
```

**Итого**: мы научились отображать свойства компонента.

[Исходный код](https://github.com/maxfarseer/react-course-ru-v2/tree/chp3-passing-props-to-news) на текущий момент. Не забудьте удалить console.log.
