ОБНОВЛЕНИЕ 2018: в учебнике хорошая теория, но ему уже два года. Проверяйте версии пакетов. За выходом нового учебника можно следить в или
На так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы, !
Порефакторим...
Для начала, удалите вовсе компонент <Comments />
(и var Comments =...
соответственно).
Далее, давайте представим: у наших новостей появляются какие-то дополнительные поля, пользователь начинает взаимодействовать с ними, например "пометить как прочитанное" и так далее. Нам было бы удобно, чтобы каждая новость была представлена компонентом.
Задача : <News />
должен рендерить список компонентов <Article />
. Каждый компонент <Article />
должен получать соответствующие данные, например: первый экземпляр получит первый элемент массива, второй - второй и так далее.
То есть, раньше в map мы возвращали JSX-разметку. Но мы так же можем возвращать и компонент.
Попробуйте сами, а потом смотрите решение ниже.
Подсказка #1 : if-else нашего компонента <News />
Copy if (data.length > 0) {
newsTemplate = data.map(function(item, index) {
return (
<div key={index}>
<Article data={item} />
</div>
)
})
} else {
newsTemplate = <p>К сожалению новостей нет</p>
}
Подсказка #2 (по сути решение задачи): компонент <Article />
Copy 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>
заголовок - "Новости".
Copy var App = React.createClass({
render: function() {
return (
<div className="app">
<h3>Новости</h3>
<News data={my_news} />
</div>
);
}
});
Добавьте красоты (CSS) по вкусу, либо возьмите мой вариант:
css/app.css
Copy .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
Copy 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 . Как вы помните, у нас там было условие:
Copy <strong className={data.length > 0 ? '':'none'}>Всего новостей: {data.length}</strong>
Так как атрибут class (либо в JSX - classname ) у элемента принимает строку, то можно представить элемент с несколькими классами:
Copy <div className={ 'class1' + 'class2' + 'class3' }>text</div>
В таком случае к нашему элементу применится ... класс "class1class2class3" , что естественно, так как мы забыли пробелы. Наверное, мы хотели сделать так:
Copy <div className={ 'class1 ' + 'class2 ' + 'class3' }>text</div>
Теперь у нас будет элемент с классами: class1, class2, class3
Именно поэтому, мы и получили следующее выражение:
Copy <strong className={'news__count ' + (data.length > 0 ? '':'none') }>Всего новостей: {data.length}</strong>
Посмотрим, что вышло в итоге: