Экосистема React в 2021 году
Tags: react, webdev
Published: 2021-01-25 16:51:21

Вольный перевод [статьи](https://daveceddia.com/react-ecosystem-overview/)

Как лучше всего создавать приложения на React в 2021 году? Что изменилось с 2016 года? Какие библиотеки сейчас все используют?

Этот пост вдохновлен теперь удаленным [постом](https://old.reddit.com/r/reactjs/comments/jb1vo8/my_react_skills_are_out_of_date_how_do_i_remain/) Reddit от человека, который изучал React в 2016 году и был обеспокоен тем, как вернуться к нему и освежить свои навыки.

Я сам начал использовать и преподавать React в 2016 году. За последние несколько лет в самом React произошли большие изменения, и экосистема тоже немного изменилась.

Вот как обстоят дела в 2021 году.

## Мышление в React: практически то же самое
Основной навык «мышления на React» за эти годы практически не изменился. Речь по-прежнему идет об одностороннем потоке данных, props, state и JSX. Такие вещи, как возможность разбить проект на компоненты, по-прежнему имеют решающее значение, как и решение, какие компоненты должны «владеть» данными, а какие - просто отображать их. 

Я по-прежнему выступаю за изучение чистого «ванильного» React, прежде чем добавлять кучу библиотек. (Конечно, я написал об этом [книгу](https://daveceddia.com/pure-react/), но если серьезно - гораздо легче выучить что-то одно за раз)

## Хуки против классов: большинство новых компонентов React используют хуки

В последние годы наибольший переход в React произошел от классов к [хукам](https://daveceddia.com/react-hooks/). Хуки были добавлены в React 16.8 (февраль 2019 г.) и довольно быстро стали стандартным способом написания компонентов React. Вы можете ознакомиться с [введением в хуки](https://daveceddia.com/intro-to-hooks/), которое я написал, когда они были впервые объявлены - сейчас они работают так же, как и тогда.

Поначалу хуки выглядят странно, особенно если вы давно занимаетесь программированием. Переменные, которые, казалось бы, поддерживают состояние между вызовами функций, кажутся довольно волшебными. Но тут больше [о массивах, чем о магии](https://daveceddia.com/intro-to-hooks/#the-magic-of-hooks).

Как только вы освоитесь с тем, как работают хуки, и почувствуете, что такое [useState](https://daveceddia.com/usestate-hook-examples/), следующим серьезным препятствием, которое необходимо преодолеть, станет [хук useEffect](https://daveceddia.com/useeffect-hook-examples/).

useEffect - это ответ на вопрос, как реализовать методы жизненного цикла в функциональных компонентах. Только он вообще не работает так, как жизненные циклы. Очень важно усвоить [ментальную модель useEffect](https://useeffectoverlunch.com/). Как только вы это сделаете, решение проблем станет проще и легче.

## Лучшие библиотеки React в 2021 году
Что касается библиотеки, фавориты сообщества с годами изменились и продолжают развиваться.

### Routing (маршрутизация)
[React Router](https://reactrouter.com/) по-прежнему является доминирующим роутером (и, несмотря на название, на самом деле не является частью самого React). В настоящее время это версия 5 (почти 6), и API немного изменился по сравнению с более ранними версиями. Меньше «объявляйте свои роуты наверху» и больше «роуты являются компонентами; возьми их куда угодно». Документация [охватывает v5](https://reactrouter.com/web/guides/quick-start), а для v6 есть [превью блог](https://reacttraining.com/blog/react-router-v6-pre/). API v6 на самом деле ближе к v3, и, поработав немного, я думаю, это будет хороший API.

### State Management
[Redux](https://redux.js.org/) по-прежнему используется во многих приложениях, в последнее время он колеблется в районе 30-50%. Новый официальный [Redux Toolkit](https://redux-toolkit.js.org/) тоже отличный. Он помогает немного сократить бойлерплейтный код в сочетании с Redux хуком. Если вы собираетесь использовать Redux, обязательно ознакомьтесь с ним.

Тем не менее, Redux в меньшей степени является стандартом де-факто, чем был раньше. Все больше людей понимают, что встроенного в React управления состоянием достаточно для множества сценариев использования, особенно для тривиальных задач.

Есть также несколько новых специализированных библиотек для вещей, для которых вы, возможно, использовали Redux раньше. Я упомяну пару ниже.

[MobX](https://mobx.js.org/README.html) - вероятно, самая популярная альтернатива Redux за пределами встроенного Context API. В то время как Redux это о явность и функциональности, MobX использует противоположный подход. Он незаметно использует Proxy ES6 для обнаружения изменений, поэтому обновление observable (наблюдаемых) данных так же просто, как использование простого оператора присваивания `=`.

Я использовал [MobX State Tree](https://mobx-state-tree.js.org/intro/welcome) в одном проекте, и мне понравилось работать с ним. Хорошо, если вам нужно управлять большим количеством состояний и вы хотите создать вокруг них структуру с помощью моделей.

[Recoil](https://recoiljs.org/) и [Zustand](https://github.com/pmndrs/zustand) - это еще пара легких вариантов управления состоянием.

В области state management, как всегда, есть много вариантов.

### Context API
Если ваше глобальное состояние состоит из пары вещей, которые редко меняются (текущий пользователь, текущая тема, текущий язык и т.д.), вам не нужна библиотека для пробрасывания этих данных.

Context API + [useContext](https://daveceddia.com/usecontext-hook/) хорош для передачи простого глобального состояния, управляемого через [useReducer](https://daveceddia.com/usereducer-hook-examples/).

Context API был переделан в React 16.3. Старый contextType убран, а старое руководство по избеганию Context, если вы не являетесь меинтейнером библиотеки, на некоторое время исчезло. [Хук useContext](https://daveceddia.com/usecontext-hook/) делает его действительно удобным.

Существует давняя путаница относительно того, использовать ли Context или Redux, и в чем заключаются различия. Прочтите сообщение в блоге от Mark Erikson о[ Context vs Redux ](https://dev.to/balaevarif/react-context-state-management-redux-2fk6)для более подробного сравнения.

### Загрузка данных 
Что касается получения данных, стратегия помещения всего в Redux или глобальное хранилище становится все менее распространенной.

[react-query](https://react-query.tanstack.com/overview) хорошо справляется с получением данных и управлением состояниями загрузки/успеха/ошибки. Он заботится о поддержании глобального кэша данных через границы компонентов, при этом вам не нужно об этом думать. ИМХО, верная абстракция. Определенно стоит посмотреть.

### Почему react-query?
Дело не столько в конкретной библиотеке, сколько в паттерне. ([swr](https://github.com/vercel/swr) - еще один хороший вариант)

Возьмем обычный сценарий, например ListPage/DetailPage для списка элементов. Вы открываете ListPage, он подгружает все виджеты или что-то еще. Пока хорошо.

Обычно вы, вероятно, кладете все данные в Redux или что-то в этом роде, так что, когда вы нажимаете на одну из страниц DetailPages, соответствующий элемент из списка, вероятно, уже был загружен. (о! но что, если пользователь загружает страницу DetailPage напрямую? Получается, нужно получить этот элемент отдельно)

Затем пользователь нажимает кнопку «Назад», и он снова возвращается на страницу ListPage, но у вас уже есть данные, поэтому вы можете просто отобразить их.

Все работает нормально, но есть исключения. Что, если элемент устарел между моментом, когда пользователь загрузил ListPage и щелкает по странице DetailPage? Что, если во время просмотра страницы DetailPage в список будут добавлены новые элементы?

Когда нужно повторно получить эти данные? И как вы справляетесь с объединением этих двух вещей - ответа списка, который может заменить весь список, и ответа с одним элементом, который должен заменять только один элемент? В Redux этим занимается редьюсер, но по большей части это приходится писать вручную.

Все становится еще сложнее, когда вы начинаете думать о разбиении на страницы и о том, хотите ли вы кэшировать страницы или повторно загружать все страницы, или что-то еще.

Я думаю, что все это подпадает под понятие «управление клиентскими данными», и мы уже давно используем для этого библиотеки управления состоянием. И мы решаем эти проблемы снова и снова, или игнорируем их и надеемся, что они не возникнут и исправляем их по мере появления.

Такие библиотеки, как react-query, по-другому решают проблему.

Она знает, что вы собираетесь получить данные, и знает, что вы захотите закэшировать эти данные глобально под каким-то ключом (например, `items` или `items[id]`). Она также знает, что вы иногда захотите обновить эти данные - на основе таймера, или когда пользователь переключается из приложения и обратно, и т.д.

Поскольку эти данные хранятся в глобально доступном кэше, каждый компонент, которому требуется доступ, может вызывать `useQuery('items', fetchItems)` для получения этих данных, и они будут автоматически извлечены, если они еще не доступны. И он также имеет дело с состояниями/загрузки/ошибки/успеха.

Он принимает любую функцию, возвращающую Promise, поэтому он работает с fetch, axios или любым другим инструментом подгрузки данных, который вы хотите использовать.

Это то, что я имел в виду, когда сказал, что, по моему мнению, у него верная абстракция  - мы можем использовать все, что уже использовали для выполнения HTTP-запроса, но при этом выполняется react-query, чтобы справиться с часто повторяющимся тяжелым объемом, характерным для большинства кейсов подгрузки данных.

### State Machines потрясающи
[XState](https://github.com/davidkpiano/xstate) - это библиотека для создания стейт машин, которые отлично подходят для представления сложной логики. На самом деле, они неплохо подходят и для несложной логики. В следующий раз, когда вы обнаружите, что жонглируете кучей логических значений или пытаетесь обновить кучу переменных в нужных местах, обратите внимание на XState. У egghead.io есть хороший [курс по XState](https://egghead.io/courses/introduction-to-state-machines-using-xstate) от Kyle Shevlin.

Существует альтернатива под названием [Robot](https://thisrobot.life/), и я написал туториал, где использовал ее для построения потока модалки подтверждения, если вы хотите понять, насколько могут быть полезны стейт машины.

### Сборщики
[Webpack](https://webpack.js.org/) по-прежнему везде. Сейчас он версии 5. Синтаксис конфига сильно изменился где-то около v2 или v3.

В настоящее время большинство людей используют [Create React App](https://github.com/facebook/create-react-app) для запуска новых приложений, что прекрасно и защищает вас от Webpack, если вам действительно не нужно его настраивать. Значения по умолчанию довольно надежны. Если вам нужно кастомизировать, обратите внимание на [Craco](https://github.com/gsoft-inc/craco).

CodeSandbox отлично подходит для создания быстрой демонстрации, и у них даже есть удобный https://react.new URL-адрес, по которому вы сразу перейдете в новый проект.

### Формы
История форм продолжает развиваться. Я помню, как много лет назад использовал redux-form, и как приложение зависало каждый раз, когда я нажимал клавишу 😂 Оглядываясь назад, можно сказать, что «держать каждую унцию состояния в Redux» никогда не было хорошей идеей.

[Formik](https://formik.org/) и [react-hook-form](https://react-hook-form.com/) кажутся фаворитами сейчас, а формы на хуках набирают обороты.

### Suspense
Долгожданная фича Suspense в React... все еще ожидается. Прямо сейчас она находится в React, и вы можете попробовать ее, но она находится в экспериментальном режиме, и создавать с ее помощью код для прода не рекомендуется. API все еще может измениться.

### Server Components 
Последнее достижение - это компоненты, которые рендерятся на сервере, в сочетании с server-side фреймворком на основе React. Они тоже пока экспериментальные. Очень круто, и я подозреваю, что это немного изменит экосистему. Посмотрите [официальное объявление и демо](https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html) от команды React, чтобы узнать больше.