Порефакторим...

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

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

Порефакторим...

Для начала, удалите вовсе компонент <Comments />var Comments =... соответственно).

Далее, давайте представим: у наших новостей появляются какие-то дополнительные поля, пользователь начинает взаимодействовать с ними, например "пометить как прочитанное" и так далее. Нам было бы удобно, чтобы каждая новость была представлена компонентом.

Задача: <News /> должен рендерить список компонентов <Article />. Каждый компонент <Article /> должен получать соответствующие данные, например: первый экземпляр получит первый элемент массива, второй - второй и так далее.

То есть, раньше в map мы возвращали JSX-разметку. Но мы так же можем возвращать и компонент.

Попробуйте сами, а потом смотрите решение ниже.

Подсказка #1: if-else нашего компонента <News />

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

Подсказка #2 (по сути решение задачи): компонент <Article />

var Article = React.createClass({
  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>
    )
  }
});

Что любопытно, больше не изменилось ни-че-го.

Замените фразу "всем привет, я компонент App..." на обычный <h3> заголовок - "Новости".

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

Добавьте красоты (CSS) по вкусу, либо возьмите мой вариант:

css/app.css

.none {
  display: none !important;
}

body {
  background: rgba(0, 102, 255, 0.38);
  font-family: sans-serif;
}

p {
  margin: 0 0 5px;
}

.article {
  background: #FFF;
  border: 1px solid rgba(0, 89, 181, 0.82);
  width: 600px;
  margin: 0 0 5px;
  box-shadow: 2px 2px 5px -1px rgb(0, 81, 202);
  padding: 3px 5px;
}

.news__author {
  text-decoration: underline;
  color: #007DDC;
}
.news__count {
  margin: 10px 0 0 0;
  display: block;
}

С новыми стилями, код сценария выглядит так:

js/app.js

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

var Article = React.createClass({
  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>
    )
  }
});

var News = React.createClass({
  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>
    );
  }
});

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

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

Обратите внимание, я добавил несколько классов, один из них я добавил к тэгу strong. Как вы помните, у нас там было условие:

<strong className={data.length > 0 ? '':'none'}>Всего новостей: {data.length}</strong>

Так как атрибут class (либо в JSX - classname) у элемента принимает строку, то можно представить элемент с несколькими классами:

<div className={ 'class1' + 'class2' + 'class3' }>text</div>

В таком случае к нашему элементу применится ... класс "class1class2class3", что естественно, так как мы забыли пробелы. Наверное, мы хотели сделать так:

<div className={ 'class1 ' + 'class2 ' + 'class3' }>text</div>

Теперь у нас будет элемент с классами: class1, class2, class3

Именно поэтому, мы и получили следующее выражение:

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

Посмотрим, что вышло в итоге:

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

Last updated