Книга: react-course-ru-v2
Назад: Создание компонента
Дальше: If-else, тернарный оператор

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

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

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

Общий вид:

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-тэга массив с данными

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

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

index.html

... 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

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

<News posledine_novosti={my_news} /> 

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

last news


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

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

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

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

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

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

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. Если вы незнакомы с ним, .

  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

... 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>     )   } } ... 

Посмотрим что получилось: новости отображены

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

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

Взглянем в консоль: no magic news screen

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


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

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

P.S. Здесь и в продолжении всего курса в коде для отображения массива новостей используется key = {index}. Обратите внимание на следующую ветку (спасибо DeLaVega и geakstr).

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

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

index.html

... 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>     )   } } ... 

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

на текущий момент. Не забудьте удалить console.log.

Назад: Создание компонента
Дальше: If-else, тернарный оператор