ОБНОВЛЕНИЕ 2018: в учебнике хорошая теория, но ему уже два года. Проверяйте версии пакетов. За выходом нового учебника можно следить в telegram канале или twitter
На канале так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы, присоединяйтесь !
Порефакторим...
Для начала, удалите вовсе компонент <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 5 px ;
}
.article {
background : #FFF ;
border : 1 px solid rgba (0 , 89 , 181 , 0.82) ;
width : 600 px ;
margin : 0 0 5 px ;
box-shadow : 2 px 2 px 5 px -1 px rgb (0 , 81 , 202) ;
padding : 3 px 5 px ;
}
.news__author {
text-decoration : underline ;
color : #007DDC ;
}
.news__count {
margin : 10 px 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 >
Посмотрим, что вышло в итоге:
Исходный код на данный момент.