Книга: react-course-ru-v2
Назад: Итоги по основам
Дальше: Приборка и импорты

create-react-app

Create-react-app

Здесь я буду предельно краток: facebook выкатили удобный . Поддерживается новый синтаксис, импорты, тестирование, перезагрузка страницы при изменениях, линтер и многое другое.

Во всем разнообразии мы сейчас разбираться не будем. Цель: разбить index.html на компоненты, подключить их, навести порядок.

Скопируйте index.html куда-нибудь на память, скоро мы разобьем его на мелкие удобные компоненты.

Установка и запуск create-react-app

npx create-react-app my-app cd my-app npm start 

Если вы не знакомы с данными командами, значит вам нужно поставить себе и ввести их в терминале после.


После запуска мы получим следующую картину в браузере:

welcome to react

И следующую файловую структуру:

+-- node_modules (здесь расположены пакеты для работы приложения) +-- public (здесь расположены публичные файлы, такие как index.html и favicon) +-- src (здесь сейчас уже живет компонент App) +-- .gitignore (файл для гита) +-- package.json (файл с зависимостями проекта) +-- README.md (описание проекта) +-- yarn.lock (может быть, а может и не быть - тоже относится к теме зависимостей проекта) 

Восстановим баланс в src

src/App.css (копируем все наши стили)

.none {   display: none; }  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; } .test-input {   margin: 0 5px 5px 0; }  .add {   margin: 0 5px 5px 0;   width: 210px;   border: 1px dashed rgba(0, 89, 181, 0.82);   padding: 5px; } .add__author, .add__text, .add__btn, .add__checkrule {   display: block;   margin: 0 0 5px 0;   padding: 5px;   width: 94%;   border: 1px solid rgba(0, 89, 181, 0.82); } .add__checkrule {   border: none;   font-size: 12px; } .add__btn {   box-sizing: content-box;   color: #FFF;   text-transform: uppercase;   background: #007DDC; } .add__btn:disabled {   background: #CCC;   color: #999; } 

src/App.js (копируем почти все из тэга script)

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 - перезагружает страницу в браузере.

prop types problem

У нас нет PropTypes в проекте. Так как раньше это был тэг script, а теперь нам нужен npm-пакет.

Остановите работу create-react-app в терминале и добавьте пакет

npm install --save prop-types 

Я не привожу сюда примеров для yarn, так как если у вас yarn вы итак в курсе, как ставить пакеты через него.

Подключите PropTypes в начале файла:

src/App.js

import React from 'react' import PropTypes from 'prop-types' import './App.css' ... 

Запустите приложение еще раз:

npm start 

news cra works

Итого: мы перевели приложение на CRA.

на данный момент (добавлен конфиг для преттира - .prettierrc, не обращайте внимание).

Назад: Итоги по основам
Дальше: Приборка и импорты