create-react-app
Здесь я буду предельно краток: facebook выкатили удобный инструмент для старта приложения. Поддерживается новый синтаксис, импорты, тестирование, перезагрузка страницы при изменениях, линтер и многое другое.
Во всем разнообразии мы сейчас разбираться не будем. Цель: разбить index.html на компоненты, подключить их, навести порядок.
Скопируйте index.html куда-нибудь на память, скоро мы разобьем его на мелкие удобные компоненты.
Установка и запуск create-react-app
1
npx create-react-app my-app
2
cd my-app
3
npm start
Copied!
Если вы не знакомы с данными командами, значит вам нужно поставить себе node.js и ввести их в терминале после.
После запуска мы получим следующую картину в браузере:
welcome to react
И следующую файловую структуру:
1
+-- node_modules (здесь расположены пакеты для работы приложения)
2
+-- public (здесь расположены публичные файлы, такие как index.html и favicon)
3
+-- src (здесь сейчас уже живет компонент App)
4
+-- .gitignore (файл для гита)
5
+-- package.json (файл с зависимостями проекта)
6
+-- README.md (описание проекта)
7
+-- yarn.lock (может быть, а может и не быть - тоже относится к теме зависимостей проекта)
Copied!
Восстановим баланс в src
src/App.css (копируем все наши стили)
1
.none {
2
display: none;
3
}
4
5
body {
6
background: rgba(0, 102, 255, 0.38);
7
font-family: sans-serif;
8
}
9
10
p {
11
margin: 0 0 5px;
12
}
13
14
.article {
15
background: #FFF;
16
border: 1px solid rgba(0, 89, 181, 0.82);
17
width: 600px;
18
margin: 0 0 5px;
19
box-shadow: 2px 2px 5px -1px rgb(0, 81, 202);
20
padding: 3px 5px;
21
}
22
23
.news__author {
24
text-decoration: underline;
25
color: #007DDC;
26
}
27
.news__count {
28
margin: 10px 0 0 0;
29
display: block;
30
}
31
.test-input {
32
margin: 0 5px 5px 0;
33
}
34
35
.add {
36
margin: 0 5px 5px 0;
37
width: 210px;
38
border: 1px dashed rgba(0, 89, 181, 0.82);
39
padding: 5px;
40
}
41
.add__author, .add__text, .add__btn, .add__checkrule {
42
display: block;
43
margin: 0 0 5px 0;
44
padding: 5px;
45
width: 94%;
46
border: 1px solid rgba(0, 89, 181, 0.82);
47
}
48
.add__checkrule {
49
border: none;
50
font-size: 12px;
51
}
52
.add__btn {
53
box-sizing: content-box;
54
color: #FFF;
55
text-transform: uppercase;
56
background: #007DDC;
57
}
58
.add__btn:disabled {
59
background: #CCC;
60
color: #999;
61
}
Copied!
src/App.js (копируем почти все из тэга script)
1
import React from 'react'; // подключение библиотеки React
2
import './App.css'; // подключение файла стилей
3
4
// далее скопировано из тэга script
5
6
const myNews = [
7
{
8
id: 1,
9
author: "Саша Печкин",
10
text: "В четверг, четвертого числа...",
11
bigText:
12
"в четыре с четвертью часа четыре чёрненьких чумазеньких чертёнка чертили чёрными чернилами чертёж."
13
},
14
{
15
id: 2,
16
author: "Просто Вася",
17
text: "Считаю, что $ должен стоить 35 рублей!",
18
bigText: "А евро 42!"
19
},
20
{
21
id: 3,
22
author: "Max Frontend",
23
text: "Прошло 2 года с прошлых учебников, а $ так и не стоит 35",
24
bigText: "А евро опять выше 70."
25
},
26
{
27
id: 4,
28
author: "Гость",
29
text: "Бесплатно. Без смс, про реакт, заходи - https://maxpfrontend.ru",
30
bigText:
31
"Еще есть группа VK, telegram и канал на youtube! Вся инфа на сайте, не реклама!"
32
}
33
];
34
35
class Article extends React.Component {
36
state = {
37
visible: false
38
};
39
handleReadMoreClck = e => {
40
e.preventDefault();
41
this.setState({ visible: true });
42
};
43
render() {
44
const { author, text, bigText } = this.props.data;
45
const { visible } = this.state;
46
return (
47
<div className="article">
48
<p className="news__author">{author}:</p>
49
<p className="news__text">{text}</p>
50
{!visible && (
51
<a
52
onClick={this.handleReadMoreClck}
53
href="#"
54
className="news__readmore"
55
>
56
Подробнее
57
</a>
58
)}
59
{visible && <p className="news__big-text">{bigText}</p>}
60
</div>
61
);
62
}
63
}
64
65
Article.propTypes = {
66
data: PropTypes.shape({
67
id: PropTypes.number.isRequired, // добавили id, это число, обязательно
68
author: PropTypes.string.isRequired,
69
text: PropTypes.string.isRequired,
70
bigText: PropTypes.string.isRequired
71
})
72
};
73
74
class News extends React.Component {
75
renderNews = () => {
76
const { data } = this.props;
77
let newsTemplate = null;
78
79
if (data.length) {
80
newsTemplate = data.map(function(item) {
81
return <Article key={item.id} data={item} />;
82
});
83
} else {
84
newsTemplate = <p>К сожалению новостей нет</p>;
85
}
86
87
return newsTemplate;
88
};
89
render() {
90
const { data } = this.props;
91
92
return (
93
<div className="news">
94
{this.renderNews()}
95
{data.length ? (
96
<strong className={"news__count"}>
97
Всего новостей: {data.length}
98
</strong>
99
) : null}
100
</div>
101
);
102
}
103
}
104
105
News.propTypes = {
106
data: PropTypes.array.isRequired
107
};
108
109
class Add extends React.Component {
110
state = {
111
name: "",
112
text: "",
113
bigText: "",
114
agree: false
115
};
116
onBtnClickHandler = e => {
117
e.preventDefault();
118
const { name, text, bigText } = this.state;
119
this.props.onAddNews({
120
id: +new Date(),
121
author: name,
122
text,
123
bigText
124
});
125
};
126
handleChange = e => {
127
const { id, value } = e.currentTarget;
128
this.setState({ [id]: e.currentTarget.value });
129
};
130
handleCheckboxChange = e => {
131
this.setState({ agree: e.currentTarget.checked });
132
};
133
validate = () => {
134
const { name, text, agree } = this.state;
135
if (name.trim() && text.trim() && agree) {
136
return true;
137
}
138
return false;
139
};
140
render() {
141
const { name, text, bigText, agree } = this.state;
142
return (
143
<form className="add">
144
<input
145
id="name"
146
type="text"
147
onChange={this.handleChange}
148
className="add__author"
149
placeholder="Ваше имя"
150
value={name}
151
/>
152
<textarea
153
id="text"
154
onChange={this.handleChange}
155
className="add__text"
156
placeholder="Текст новости"
157
value={text}
158
/>
159
<textarea
160
id="bigText"
161
onChange={this.handleChange}
162
className="add__text"
163
placeholder="Текст новости подробно"
164
value={bigText}
165
/>
166
<label className="add__checkrule">
167
<input type="checkbox" onChange={this.handleCheckboxChange} /> Я
168
согласен с правилами
169
</label>
170
<button
171
className="add__btn"
172
onClick={this.onBtnClickHandler}
173
disabled={!this.validate()}
174
>
175
Показать alert
176
</button>
177
</form>
178
);
179
}
180
}
181
182
Add.propTypes = {
183
onAddNews: PropTypes.func.isRequired
184
};
185
186
class App extends React.Component {
187
state = {
188
news: myNews
189
};
190
handleAddNews = data => {
191
const nextNews = [data, ...this.state.news];
192
this.setState({ news: nextNews });
193
};
194
render() {
195
return (
196
<React.Fragment>
197
<Add onAddNews={this.handleAddNews} />
198
<h3>Новости</h3>
199
<News data={this.state.news} />
200
</React.Fragment>
201
);
202
}
203
}
204
205
// скопировано все кроме ReactDOM.render
206
207
// добавился export
208
export default App;
Copied!
Удалите файл src/Logo.svg, остальное не трогайте, но можете посмотреть :)
Create-react-app (CRA) при каждом изменении в файлах внутри директории src - перезагружает страницу в браузере.
prop types problem
У нас нет PropTypes в проекте. Так как раньше это был тэг script, а теперь нам нужен npm-пакет.
Остановите работу create-react-app в терминале и добавьте пакет prop-types
1
npm install --save prop-types
Copied!
Я не привожу сюда примеров для yarn, так как если у вас yarn вы итак в курсе, как ставить пакеты через него.
Подключите PropTypes в начале файла:
src/App.js
1
import React from 'react'
2
import PropTypes from 'prop-types'
3
import './App.css'
4
...
Copied!
Запустите приложение еще раз:
1
npm start
Copied!
news cra works
Итого: мы перевели приложение на CRA.
Исходный код на данный момент (добавлен конфиг для преттира - .prettierrc, не обращайте внимание).
Last modified 1yr ago
Copy link