Здесь я буду предельно краток: facebook выкатили удобный . Поддерживается новый синтаксис, импорты, тестирование, перезагрузка страницы при изменениях, линтер и многое другое.
Во всем разнообразии мы сейчас разбираться не будем. Цель: разбить index.html на компоненты, подключить их, навести порядок.
Скопируйте index.html куда-нибудь на память, скоро мы разобьем его на мелкие удобные компоненты.
Установка и запуск create-react-app
npx create-react-app my-app cd my-app npm start
Если вы не знакомы с данными командами, значит вам нужно поставить себе и ввести их в терминале после.
После запуска мы получим следующую картину в браузере:
И следующую файловую структуру:
+-- 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 - перезагружает страницу в браузере.
У нас нет 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
Итого: мы перевели приложение на CRA.
на данный момент (добавлен конфиг для преттира - .prettierrc, не обращайте внимание).