# Использование 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.


---

# 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/ispolzovanie-props.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.
