Прежде чем мы приступим к делу, скажем пару слов о том, почему React можно считать наилучшей альтернативой среди средств для разработки веб-интерфейсов.
React-разработка заключается в описании того, что нужно вывести на страницу (а не в составлении инструкций для браузера, посвящённых тому, как это делать). Это, кроме прочего, означает значительное сокращение объёмов шаблонного кода.
В React применяется синтаксис JSX, который воспринимается как обычный HTML (но не является ни строкой, ни HTML). Он максимально ясно описывает внешний вид UI, одновременно включая в себя всю мощь JavaScript. Вот как это выглядит:
const element = <h1>Hello, world!</h1>;
const Greetings = ({ firstName }) => (
<div>Hi, {firstName}</div> // в JSX фигурные скобки используются для выражений
);
Подробнее о выражениях.
В React используется односторонняя привязка данных: от родительского элемента к дочерним. Это — большой плюс: вы всегда знаете что привело к изменению состояния приложения. Подобный подход к привязке данных значительно упрощает отладку.
Компонентный подход React похож на компоненты Figma или символы Sketch. Компоненты можно вкладывать друг в друга и переопределять стили.
Кривая обучения — это важный фактор, который нужно учитывать при выборе UI-фреймворка. В этой связи надо отметить, что в React имеется меньше абстракций, чем, скажем, в Angular. Для того, чтобы разобраться, потребуется некоторое время, но приступить к работе можно очень и очень быстро.
html, css. javascript:
- Типы данных mdn, learnjs
- Массивы mdn Методы работы с массивами: filter, map, reduce, find, библиотека lodash
- Шаблонные строки mdn, learnjs (обратите внимание на `кавычки`)
- Циклы mdn, learnjs
- Функции mdn (обратите внимание на краткую запись =>, скоуп)
- Модули import, export, модули в рамках React, шпаргалка на stackoverflow
- Объекты mdn
- События mdn. Что такое preventDefault, stopPropagation
- Классы в React
- DOM в React, как работает. Схема работы
- State (состояния): оф.документация, еще теория
- LifeCycle (жизненный цикл): оф.документация. Статьи по теме: 1, 2, 3
- Routing (роутинг): туториал
Официальная документация: en ru
Шпаргалка по библиотеке для версий 15 и 16 (en)
кратко изложены методы и подходы в виде сниппетов кода
Книга Реакт быстро (ru)
подробное, пошаговое описание для старта работы (максимально развернуто)
Видео основы React от создателя Framer (en)
нет описания
Видеокурс основы React (ru)
база для старта
Книга-курс для начинающих (ru)
пошаговое создание небольшого приложения новостей (добавление, просмотр "подробнее")
Видео-курс с практикой (en)
пошаговое создание to do app
Курс Евгения Родионова: этап 1, этап 2, этап 3 (ru)
нет описания
Всё, что нужно знать, чтобы войти в React (ru)
статья с основными концепциями
JavaScript fundamentals before learning React (en)
Автор предлагает список основ js перед стартом React
Статьи по react (en)
на разные темы
! Автор тутора предполагает, что вы ознакомились с базой js и базой библиотеки React. Задания направлены на закрепление знаний и привыкание к синтаксису.
! Для мышечной памяти весь код шагов рекомендуется переписывать самостоятельно, а не копировать.
Для удобства в репозитории уже есть create-react-app
. Клоним, устанавливаем зависимости:
git clone https://github.com/object-of-obsession/react.git
cd react
npm i
app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html // здесь будет рендериться приложение
│ └── manifest.json // манифест
└── src
├── App.css // стили компонента App
├── App.js // файл компонента App
├── App.test.js // тесты компонента App
├── index.css // стили страницы index.html
├── index.js // файл с инструкцией рендеринга
├── logo.svg // графика, используемая в приложении
└── serviceWorker.js // файл сервис-воркера
Почитать про манифест, сервис-воркеры
В index.js
описаны компоненты, которые необходимо отрендерить. В нашем случае это единственный App
, но их может быть больше. Если импорт описан корректно, приложение смотрит внутрь каждого компонента и собирает сопутствующие файлы: для App
это стили App.css
, графика logo.svg
. Далее метод getElementById
находит контейнер с id="root"
в public/index.html
и рендерит в html-файле компонент App
, попутно применяя к index.html
стили index.css
index.js
// импорт
import React from 'react'; // React
import ReactDOM from 'react-dom'; // ReactDOM
import './index.css'; // стили для index.html
import App from './App'; // компонент App
import * as serviceWorker from './serviceWorker'; // сервис-воркер
// метод render модуля ReactDOM, на вход (в круглых скобках) принимает два аргумента:
// компонент App и узел в html, где отрендерить компонент App*
ReactDOM.render(<App />, document.getElementById('root'));
* если не импортировать модуль ReactDOM
, метод render
не сработает, то же касается файла стилей. Всегда следите за импортами.
index.html
...
<div id="root"></div> // здесь React рендерит компонент App
...
App.js (может иметь расширение как js
, так и jsx
— как вам нравится)
// импорт
import React from 'react'; // React, нужен для создания функционального компонента и читения JSX
import logo from './logo.svg'; // графика
import './App.css'; // стили компонента
// компонент App, функциональный*
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App; // экспорт компонента App
* в React компоненты делятся на функциональные и классовые, почитать
Обратите внимание, что в теле return
есть один общий div
с className="App"
, в него завернуто тело компонента. Дело в том, что в React функция может вернуть разметку, завернутую в один тег будь то section, link, div, etc.
Содержимое css файлов вам знакомо, сервис-воркеры не понадобятся.
В нашей обучалке мы закастомим create-react-app
:
- изменим структуру файлов
- добавим несколько компонентов
- научимся стилизовать компоненты
- настроим роутинг
Этот флоу похож на некоторые моменты работы дизайнера в графических редакторах. Последний пункт поможет связывать разные страницы в рамках одной задачи.
Чтобы начать работу установите react dev tools
для вашего браузера, в терминале выполните:
npm start
Компонентный подход — мощная парадигма, используемая в разработке и в дизайне. Если взглянуть на работу в Sketch, каждый символ лежит на своем артборде (в React символ = компонент). Попоробуем применить этот подход в проекте. Дефолтный create-react-app
складывает файлы в /src
. Если компонентов будет больше, поддержка затруднится.
Вытащим комопнент App.js
, App.css
, App.test.js
в свою папку c названием App
. Получим структуру
внутри src
:
└── src
└── App
├── App.css
├── App.js
└── App.test.js
├── index.css
├── index.js
├── logo.svg
└── serviceWorker.js
Если вы успели посмотреть, страница браузера/консоль/терминал выдают ошибку:
Failed to compile.
...
Error: ENOENT: no such file or directory / can't resolve path ...
Мы переместили файлы, но не изменили пути импорта. Без исправления билд не запустится.
Посомтрим в index.js
. Он использует перемещённый компонент App
.
// index.js
import App from './App';
./
означает, что index.js
будет искать компонент в src
(в той папке, где находится сам), нам нужна папка с имененем компонента App
:
// index.js
import App from './App/App';
Есть еще ошибка, связанная с svg-файлом. Попробуйте разобраться в чем дело.
Все новые компоненты будем складывать по папкам с именем компонента в /src
, имя папки должно начинаться с большой буквы, так React поймет, что это хранилище компонета. Если все ок, приступаем ко второму шагу.
Пока у нас есть единственный функциональный компонент App
. Добавим еще один компонент, но классовый. Чтобы не возиться с версткой, вытащим тег <p> и его содержимое из App.js
и сделаем его компонентом.
// App.js
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
Первым делом нужна папка с имененем компонента, назовём Instruction
. Также в папке должен пристуствовать файл самого компонента Instruction.jsx
(напомню, что файлы компонентов могут иметь расширения .js
и .jsx
. В данном случае нет связи с тем, что компонент классовый. Просто демонстрация что работает и так, и так). Получаем стуркутуру:
└── src
└── App
├── App.css
├── App.js
└── App.test.js
└── Instruction
└── Instruction.jsx
├── index.css
├── index.js
├── logo.svg
└── serviceWorker.js
В файле компонента Instruction
:
// Instruction.jsx
import React from 'react';
class Instruction extends React.Component {
render() {
return (
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
)
}
}
export default Instruction;
Сам по себе компонент Instruction
так и останется лежать в своей директории, добавим его в компонет App
:
// App.js
import React from 'react';
import logo from '../logo.svg';
import './App.css';
import Instruction from './Instruction';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
// добавили компонент Instruction
<Instruction />
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
Задание: В снипете выше для App.js
есть ошибка с импортом, попробуйте исправить её.
Если все верно, в ReactDevTools вы увидите компонент Instruction
, отрендеренный внутри App
.
Задание: в компоненте App
есть ссылка с текстом Learn React. Попробуйте создать классовый или функциональный компонент с названием Button
и заменить ссылку на кнопку. Кнопку можно сделать html-тегом button
, поведение ссылки можно не сохранять. Позже мы закастомим эту кнопку. На выходе получится так:
Мы добавили два компонента Instruction
и Button
в App
. Компоненты могут вкладывать друг в друга солько угодно, главное держать ситуацию под контролем.
В React существет несколько способов применения стилей. В этом туториале рассмотрим CSS модули, так как этот подход наиболее близок к обычной реализации через отдельные CSS файлы и классы.
Если вы обратили внимание, в директории компонента App
есть файл App.css
, он подключается в App.js
в качестве модуля. Внутри обычный css, но собака зарыта в описании классов JSX. Так как слово class
зарезервировано в js, создатели React придумали писать className="..."
.
Давайте закастомим кнопку из предыдущего задания. В репозитории лежит файл со стилями кнопки tutorial_assets/Button.css
. Попробуйте применить его к компоненту Button
.
Вторым шагом закастомим компонент Instruction
: подключите в его css файл гарнитуру Open Sans по cdn:
@import url('https://fonts.googleapis.com/css?family=Open+Sans');
Стиль для текста на ваш вкус.
Мы закастомили компоненты приложения, обязательно ознакомьтесь с другими способами стилизации в React: ru, en.
В React есть своя система маршрутизации, которая позволяет сопоставлять запросы к приложению с определенными компонентами, другими словами переходить по страницам или менять часть контента страницы по ивенту. Ключевым звеном в работе маршрутизации является модуль react-router, который содержит основной функционал по работе с маршрутизацией. Однако если мы собираемся работать в браузере, нам надо использовать модуль react-router-dom. Чтобы использовать его в туторе выполните:
npm i [email protected]
Ознакомьтесь с базовыми подходами роутинга перед началом практики.
Попробуем простой пример. Нам нужно сделать переход между двумя страницами по клику на кнопку. В компоненте App
уже есть компонент с кнопкой Button
, а сам App
является первой страницей.
Создайте компонент второй страницы с именеем Second
. В нем помимо прочих должны быть импортированы модули из react-router-dom
:
import { BrowserRouter as Router, Link } from "react-router-dom";
Second
будет возвращать следующую разметку:
<div style={{ margin: '20px' }}>
← Go back to App
</div>
Позже этот текст станет контролом, который будет возвращать пользователя на первую страницу. Обратите внимание, используется инлайновая стилизация JSX.
Теперь надо научить приложение видеть разные страницы и использовать правильный путь при переходе. Для этого Router
нужно передать как аргумент в метод ReactDOM.render
вместо App
:
// index.js
// ReactDOM.render(<App />, document.getElementById('root')); строку можно удалить
ReactDOM.render((
<Router>
<Route path="/" component={App} /> // роут 1
<Route path="/second" component={Second} /> // роут 2
</Router>
), document.getElementById('root'));
Роут 1 говорит, что компонент App
будет показан по адресу http://localhost:3000/
.
Роут 2 говорит, что компонент Second
будет показан по адресу http://localhost:3000/second
.
Таким образом в div с root
в зависимости от адреса будут рендериться разные компоненты.
Любой Route может иметь параметр exact
.
Контролам тоже нужна инструкция для перехода. Компонет Button
ведет на страницу Second
, значит он должен возвращать помимо кнопки еще и ссылку:
import React from "react"
import "./Button.css"
import { BrowserRouter as Router, Link } from "react-router-dom"; // добавлены модули для роутинга
function Button() {
return (
<Link to="/second"> // кнопка завернута в линк со ссылкой на нужный адрес
<button className="button">Learn React</button>
</Link>
)
}
export default Button;
Попробуйте обновить сборку и посмотреть, работает ли переход. Должен работать в одну сторону, обратно вернуться нельзя. Это из-за того, что в компоненте Second
текст ← Go back to App
еще не стал ссылкой и не получил адрес.
Попробуйте сделать это самостоятельно.
Если все правильно, приложение должно работать так:
Попробуйте пройтись взглядом по всем файлам в /src
и вспомнить смысл кода. Также полезно заглянуть в ReactDevTools на каждой странице — в работе с React этот плагин более информативен, чем инспектор браузера.
Если у вас есть предложения, присылайте в issues.