Здесь я буду предельно краток: facebook выкатили удобный инструмент для старта приложения . Поддерживается новый синтаксис, импорты, тестирование, перезагрузка страницы при изменениях, линтер и многое другое.
Во всем разнообразии мы сейчас разбираться не будем. Цель: разбить index.html на компоненты, подключить их, навести порядок.
Скопируйте index.html куда-нибудь на память, скоро мы разобьем его на мелкие удобные компоненты.
Установка и запуск create-react-app
Copy npx create-react-app my-app
cd my-app
npm start
Если вы не знакомы с данными командами, значит вам нужно поставить себе node.js и ввести их в терминале после.
После запуска мы получим следующую картину в браузере:
И следующую файловую структуру:
Copy +-- node_modules (здесь расположены пакеты для работы приложения)
+-- public (здесь расположены публичные файлы, такие как index.html и favicon)
+-- src (здесь сейчас уже живет компонент App)
+-- .gitignore (файл для гита)
+-- package.json (файл с зависимостями проекта)
+-- README.md (описание проекта)
+-- yarn.lock (может быть, а может и не быть - тоже относится к теме зависимостей проекта)
Восстановим баланс в src
src/App.css (копируем все наши стили)
Copy .none {
display : none ;
}
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 ;
}
.test-input {
margin : 0 5 px 5 px 0 ;
}
.add {
margin : 0 5 px 5 px 0 ;
width : 210 px ;
border : 1 px dashed rgba (0 , 89 , 181 , 0.82) ;
padding : 5 px ;
}
.add__author , .add__text , .add__btn , .add__checkrule {
display : block ;
margin : 0 0 5 px 0 ;
padding : 5 px ;
width : 94 % ;
border : 1 px solid rgba (0 , 89 , 181 , 0.82) ;
}
.add__checkrule {
border : none ;
font-size : 12 px ;
}
.add__btn {
box-sizing : content-box ;
color : #FFF ;
text-transform : uppercase ;
background : #007DDC ;
}
.add__btn:disabled {
background : #CCC ;
color : #999 ;
}
src/App.js (копируем почти все из тэга script)
Copy import React from 'react' ; // подключение библиотеки React
import './App.css' ; // подключение файла стилей
// далее скопировано из тэга script
const myNews = [
{
id : 1 ,
author : "Саша Печкин" ,
text : "В четверг, четвертого числа..." ,
bigText :
"в четыре с четвертью часа четыре чёрненьких чумазеньких чертёнка чертили чёрными чернилами чертёж."
} ,
{
id : 2 ,
author : "Просто Вася" ,
text : "Считаю, что $ должен стоить 35 рублей!" ,
bigText : "А евро 42!"
} ,
{
id : 3 ,
author : "Max Frontend" ,
text : "Прошло 2 года с прошлых учебников, а $ так и не стоит 35" ,
bigText : "А евро опять выше 70."
} ,
{
id : 4 ,
author : "Гость" ,
text : "Бесплатно. Без смс, про реакт, заходи - https://maxpfrontend.ru" ,
bigText :
"Еще есть группа VK, telegram и канал на youtube! Вся инфа на сайте, не реклама!"
}
];
class Article extends React . Component {
state = {
visible : false
};
handleReadMoreClck = e => {
e .preventDefault ();
this .setState ({ visible : true });
};
render () {
const { author , text , bigText } = this . props .data;
const { visible } = this .state;
return (
< div className = "article" >
< p className = "news__author" >{author}:</ p >
< p className = "news__text" >{text}</ p >
{ ! visible && (
< a
onClick = { this .handleReadMoreClck}
href = "#"
className = "news__readmore"
>
Подробнее
</ a >
)}
{visible && < p className = "news__big-text" >{bigText}</ p >}
</ div >
);
}
}
Article .propTypes = {
data : PropTypes .shape ({
id : PropTypes . number .isRequired , // добавили id, это число, обязательно
author : PropTypes . string .isRequired ,
text : PropTypes . string .isRequired ,
bigText : PropTypes . string .isRequired
})
};
class News extends React . Component {
renderNews = () => {
const { data } = this .props;
let newsTemplate = null ;
if ( data . length ) {
newsTemplate = data .map ( function (item) {
return < Article key = { item .id} data = {item} />;
});
} else {
newsTemplate = < p >К сожалению новостей нет</ p >;
}
return newsTemplate;
};
render () {
const { data } = this .props;
return (
< div className = "news" >
{ this .renderNews ()}
{ data . length ? (
< strong className = { "news__count" }>
Всего новостей: { data . length }
</ strong >
) : null }
</ div >
);
}
}
News .propTypes = {
data : PropTypes . array .isRequired
};
class Add extends React . Component {
state = {
name : "" ,
text : "" ,
bigText : "" ,
agree : false
};
onBtnClickHandler = e => {
e .preventDefault ();
const { name , text , bigText } = this .state;
this . props .onAddNews ({
id : +new Date () ,
author : name ,
text ,
bigText
});
};
handleChange = e => {
const { id , value } = e .currentTarget;
this .setState ({ [id] : e . currentTarget .value });
};
handleCheckboxChange = e => {
this .setState ({ agree : e . currentTarget .checked });
};
validate = () => {
const { name , text , agree } = this .state;
if ( name .trim () && text .trim () && agree) {
return true ;
}
return false ;
};
render () {
const { name , text , bigText , agree } = this .state;
return (
< form className = "add" >
< input
id = "name"
type = "text"
onChange = { this .handleChange}
className = "add__author"
placeholder = "Ваше имя"
value = {name}
/>
< textarea
id = "text"
onChange = { this .handleChange}
className = "add__text"
placeholder = "Текст новости"
value = {text}
/>
< textarea
id = "bigText"
onChange = { this .handleChange}
className = "add__text"
placeholder = "Текст новости подробно"
value = {bigText}
/>
< label className = "add__checkrule" >
< input type = "checkbox" onChange = { this .handleCheckboxChange} /> Я
согласен с правилами
</ label >
< button
className = "add__btn"
onClick = { this .onBtnClickHandler}
disabled = { ! this .validate ()}
>
Показать alert
</ button >
</ form >
);
}
}
Add .propTypes = {
onAddNews : PropTypes . func .isRequired
};
class App extends React . Component {
state = {
news : myNews
};
handleAddNews = data => {
const nextNews = [data , ... this . state .news];
this .setState ({ news : nextNews });
};
render () {
return (
< React.Fragment >
< Add onAddNews = { this .handleAddNews} />
< h3 >Новости</ h3 >
< News data = { this . state .news} />
</ React.Fragment >
);
}
}
// скопировано все кроме ReactDOM.render
// добавился export
export default App;
Удалите файл src/Logo.svg
, остальное не трогайте, но можете посмотреть :)
Create-react-app (CRA) при каждом изменении в файлах внутри директории src - перезагружает страницу в браузере.
У нас нет PropTypes в проекте. Так как раньше это был тэг script, а теперь нам нужен npm-пакет.
Остановите работу create-react-app в терминале и добавьте пакет prop-types
Copy npm install --save prop-types
Я не привожу сюда примеров для yarn, так как если у вас yarn вы итак в курсе, как ставить пакеты через него.
Подключите PropTypes в начале файла:
src/App.js
Copy import React from 'react'
import PropTypes from 'prop-types'
import './App.css'
...
Запустите приложение еще раз:
Итого : мы перевели приложение на CRA.
Исходный код на данный момент (добавлен конфиг для преттира - .prettierrc, не обращайте внимание).