Архитектура и основные модули из экосистемы Реакта
Чем в сознании разработчика библиотека отличается от фреймворка? Библиотека решает конкретную задачу, фреймворк даёт экосистему и диктует архитектуру.
Когда впервые знакомишься с Реактом, то после всяких Ангуларов не понимаешь, как же с ним работать: это же библиотека для вёрстки, почему я должен её использовать? У меня всё хорошо, есть @angular/common/http
, @angular/universal
, @angular/router
и прочее, а тут мне нужно из говна и палок слепить проект, не хочу этим заниматься!
Так-то оно правда, но вы пользуетесь Реактом в 2018 году, а не в 2014, когда ещё ничего не было, так что сегодня мы рассмотрим основные библиотеки, которые можно использовать с Реактом.
Как вы понимаете, Styled Components. Эту идеальную библиотеку пока никто не переплюнет.
Его мы тоже проходили, это Реакт-роутер.
Сравнительно новый браузерный АПИ для запросов.
Если нужна поддержка старых браузеров, используют полифилл github/fetch.
(полифилл это библиотека, которая предоставляет новую функциональность через старые технологии — например, в этом случае fetch
работает на XMLHttpRequest)
В интерфейсах часто бывают формы: инпуты, селекты и прочие поля ввода, а у форм ведь должна быть валидация данных и прочие возможности.
Formik либо react-final-form.
Стейт компонента. Да, я не шучу, в 99.99999999% случаев используйте локальный стейт компонента или его родителей.
Почему часто советуют Редакс или Мобкс? Потому что в 2015 Редакс был очень модным и все старались его воткнуть себе в проект, а потом оказалось, что он на пустом месте усложняет проект. Сам Даня Абрамов говорит, что скорее всего вам не нужен Редакс.
Либо react-portal, либо ReactDOM.createPortal().
Часто советуют Ant Design, но лично я не пользовался: у меня всегда был свой дизайн.
Тайтлы, описания, опенграф-теги обновляются через react-helmet.
moment.js слишком жирный и придерживается мутабельности — это неудобно.
Раньше был react-select, но он вообще не поддерживается автором.
Сейчас есть downshift, но это достаточно низкоуровневая библиотека, поверх которой можно строить свои компоненты — посмотрите примеры в документации.
Зависит от сервиса, который вы используете: например, google-map-react
или react-yandex-maps
.
Обычно все графики работают поверх d3.js — это самая мощная библиотека для работы с ними, посмотрите на эти демки, которые собирает автор.
vx — библиотека, которая дружит d3 и Реакт.
Обычно хватает поиска в Гугле «react x», а после остаётся только выбрать.
Вот несколько правил:
- версия желательно не должна быть 0.х: по Семверу всё может сломаться,
- понятные описания релизов: если нет файла
CHANGELOG.md
или вкладка Releases на Гитхабе пустует, то вам сложно будет обновляться, - должны быть ишью и пулл-реквесты: библиотекой должен пользоваться кто-то кроме её автора.
У вас есть CRA, который скрыл настройку Вебпака и Бейбеля под собой. Можете выдохнуть.
Едем дальше. Частый вопрос: а как организовывать проект?
Организация проекта строится по бизнес-логике: нет нужды делать кучу директорий src/components/Properties
, src/containers/Properties
, src/actions/Properties
, src/api/Properties
, если можно всё положить в src/Properties/{actions,api}
.
Объединять по доменам проще, чем бегать по 10 директориям, вы же в один момент времени работаете только с одной сущностью?
Например, вам нужно сделать авторизацию, Auth
: две страницы (логин, регистрация), несколько компонентов, запросы к серверу. Когда вы её делаете, вы же не отвлекаетесь на другие компоненты или файлы? Вы работаете конкретно над авторизацией.
Думайте продуктом, а не ненужными абстракциями типа компонентов или контейнеров. Люди в вашем продукте пользуются конкретной функциональностью, а не экшенами, редьюсерами или контейнерами.
Нет, я серьёзно: даже после предыдущего пункта люди часто оставляют директорию components
. У вас всё приложение построено на компонентах, зачем директорию отдельно создавать?
Если хотите какой-нибудь хедер или футер переиспользовать на разных страницах, то положите в корень src
, а не в src/components
или src/shared
.
Для интерфейсных вещей типа форм, кнопок и прочего обычно используют src/ui
.
Часто вижу src/Header
, в котором лежит сиротливый index.js
. Зачем? На будущее? Преждевременные оптимизации — корень всех бед.
Положите в src/Header.js
.
Это же компонентный подход, ничего страшного если в одном файле будут СК, "главный" Реакт-компонент с запросами или обработчиками событий.
Если стилей много, то ваш выбор styled.js
с экспортами рядом с файлом.
Ещё один частый вопрос: а как мелко дробить компоненты?
Дробите до переиспользуемости. Если у вас есть два огромных блока, в которых повторяется только кнопка, то вынесите кнопку в отдельный компонент, а всё остальное оставьте как есть: смысл дробить меньше?
Но если работать неудобно с компонентом — то дробите тоже.
Сегодняшним уроком я хотел вам показать, что Реакт это устоявшаяся экосистема, где либо используются стандарты (фетч), либо есть давно устоявшиеся библиотеки, заточенные чисто под Реакт.
Пример неплохой архитектуры? Например, моя неплоха, хоть и неидеальна.
src
├── About.js
├── Announces
│ ├── CourseReactAnnounce.js
│ └── index.js
├── App.js
├── Buy
│ ├── Closed.js
│ ├── Medium.svg
│ ├── Old.js
│ ├── Telegram.svg
│ ├── VK.svg
│ ├── YouTube.svg
│ ├── index.js
│ └── tinkoff.js
├── Companies
│ ├── everpoint.js
│ └── index.js
├── Courses
│ ├── Lessons
│ │ ├── Header.js
│ │ ├── Lesson.js
│ │ ├── ReactMarkdown.js
│ │ ├── Stage.js
│ │ ├── external-link.svg
│ │ └── styled.js
│ ├── React
│ │ ├── About.js
│ │ ├── Antihire.js
│ │ ├── Buy.js
│ │ ├── Changes
│ │ │ ├── clocks.svg
│ │ │ └── index.js
│ │ ├── Footer
│ │ │ ├── index.js
│ │ │ ├── md.svg
│ │ │ ├── tg.svg
│ │ │ ├── vk.svg
│ │ │ └── yt.svg
│ │ ├── Header
│ │ │ ├── atom.png
│ │ │ └── index.js
│ │ ├── History
│ │ │ ├── index.js
│ │ │ └── max.svg
│ │ ├── Kursach
│ │ │ ├── index.js
│ │ │ └── kursach.svg
│ │ ├── LandingUI.js
│ │ ├── Project
│ │ │ ├── Aviasales
│ │ │ │ ├── aviasales.svg
│ │ │ │ └── index.js
│ │ │ ├── Dates.js
│ │ │ ├── Format
│ │ │ │ ├── format.svg
│ │ │ │ ├── assistant.svg
│ │ │ │ ├── code_review.svg
│ │ │ │ └── index.js
│ │ │ └── index.js
│ │ ├── Quote.js
│ │ ├── Reviews
│ │ │ ├── Review.js
│ │ │ └── index.js
│ │ ├── SoftSkills
│ │ │ ├── index.js
│ │ │ ├── softskills_0.jpg
│ │ │ ├── softskills_0_mobile.png
│ │ │ ├── softskills_1.jpg
│ │ │ ├── softskills_1_mobile.png
│ │ │ ├── softskills_2.jpg
│ │ │ ├── softskills_2_mobile.png
│ │ │ ├── softskills_small_0.jpg
│ │ │ ├── softskills_small_0_mobile.png
│ │ │ ├── softskills_small_1.jpg
│ │ │ ├── softskills_small_1_mobile.png
│ │ │ ├── softskills_small_2.jpg
│ │ │ └── softskills_small_2_mobile.png
│ │ └── index.js
│ ├── Verstka
│ │ ├── Landing
│ │ │ ├── About.js
│ │ │ ├── Buy.js
│ │ │ ├── Chat.js
│ │ │ ├── Course.js
│ │ │ ├── Feedback
│ │ │ │ ├── bot.png
│ │ │ │ ├── chats.png
│ │ │ │ ├── code-review-feedback.png
│ │ │ │ └── index.js
│ │ │ ├── Format
│ │ │ │ ├── index.js
│ │ │ │ └── [email protected]
│ │ │ ├── Kursach
│ │ │ │ ├── [email protected]
│ │ │ │ └── index.js
│ │ │ ├── Questions
│ │ │ │ ├── Question.js
│ │ │ │ ├── data.js
│ │ │ │ └── index.js
│ │ │ ├── Reviews
│ │ │ │ ├── index.js
│ │ │ │ └── [email protected]
│ │ │ └── index.js
│ │ ├── Study
│ │ │ ├── Footer.js
│ │ │ ├── link.svg
│ │ │ ├── Lessons.js
│ │ │ ├── codeRenderer.js
│ │ │ └── styles.js
│ │ └── index.js
│ └── index.js
├── Footer
│ ├── index.js
│ ├── md.svg
│ ├── tg.svg
│ ├── vk.svg
│ └── yt.svg
├── Frontend
│ ├── About.js
│ ├── Buy.js
│ ├── Feedback
│ │ ├── [email protected]
│ │ └── index.js
│ ├── Format.js
│ ├── Kursach
│ │ ├── index.js
│ │ └── screenshot.png
│ ├── Landing.js
│ ├── LandingFeb
│ │ ├── Program.js
│ │ ├── Steps.js
│ │ ├── aviasales.png
│ │ └── index.js
│ ├── NewYearBuy.js
│ ├── Payed.js
│ ├── Plan.js
│ ├── Premium.js
│ ├── Program.js
│ ├── Questions
│ │ ├── Question.js
│ │ ├── data.js
│ │ └── index.js
│ ├── Result.js
│ ├── Reviews
│ │ ├── Navigation.js
│ │ ├── Review.js
│ │ ├── data.js
│ │ └── index.js
│ ├── Steps.js
│ ├── Study
│ │ ├── Footer.js
│ │ ├── Lessons.js
│ │ └── index.js
│ ├── data.js
│ └── index.js
├── Header.js
├── Helmet.js
├── Home
│ ├── Courses.js
│ ├── YouTube
│ │ ├── index.js
│ │ └── [email protected]
│ ├── data.js
│ └── index.js
├── Navigation.js
├── Payment
│ ├── Gift
│ │ ├── Telegram.svg
│ │ ├── [email protected]
│ │ └── index.js
│ ├── copy.svg
│ ├── fb.svg
│ ├── index.js
│ ├── ok.svg
│ ├── tw.svg
│ └── vk.svg
├── ReactRemarkable
│ ├── components.js
│ ├── index.js
│ └── toc
│ ├── index.js
│ └── utils.js
├── ScrollToTop.js
├── analytics.js
├── api.js
├── fonts
│ ├── GraphikLCG
│ │ ├── GraphikLCG-Black.eot
│ │ ├── GraphikLCG-Black.ttf
│ │ ├── GraphikLCG-Black.woff
│ │ ├── GraphikLCG-Bold.eot
│ │ ├── GraphikLCG-Bold.ttf
│ │ ├── GraphikLCG-Bold.woff
│ │ ├── GraphikLCG-Medium.eot
│ │ ├── GraphikLCG-Medium.ttf
│ │ ├── GraphikLCG-Medium.woff
│ │ ├── GraphikLCG-Regular.eot
│ │ ├── GraphikLCG-Regular.ttf
│ │ ├── GraphikLCG-Regular.woff
│ │ ├── GraphikLCG-Semibold.eot
│ │ ├── GraphikLCG-Semibold.ttf
│ │ └── GraphikLCG-Semibold.woff
│ └── KazimirText
│ ├── KazimirText-Roman.eot
│ ├── KazimirText-Roman.ttf
│ └── KazimirText-Roman.woff
├── index.css
├── index.js
├── registerServiceWorker.js
└── ui
├── Aside.js
├── Button.js
├── Code.js
├── H1.js
├── H2.js
├── H3.js
├── H4.js
├── HeroUnit.js
├── Link.js
├── P.js
├── Wrapper.js
└── index.js