React для разработчиков на Vue, Часть 5: Шпаргалка по экосистеме

Источник: Telerik Blogs•

React для разработчиков на Vue, Часть 5: Шпаргалка по экосистеме

React 19 для разработчиков на Vue, Часть 3 (ошибка в оригинале, по контексту Часть 5): держите эту шпаргалку под рукой, когда будете с комфортом переходить на инструменты React после Vue.

React 19 для разработчиков на Vue, Часть 5: держите эту шпаргалку под рукой, когда будете с комфортом переходить на инструменты React после Vue.

В Части 4 этой серии мы завершили обзор хуков форм в React 19. За четыре предыдущие части мы разобрали основные идеи, компоненты, состояние, эффекты, сервер и формы. Но базовая библиотека — это лишь половина реальной работы. Вторая половина — это окружающая ее экосистема, и именно здесь разработчик на Vue чувствует себя наиболее потерянным в первый день.

Поэтому последняя часть особенная. Это шпаргалка. То, что вы будете держать открытым во вкладке в течение первого месяца работы в команде React, чтобы, когда кто-то скажет «просто положи это в хранилище», вы понимали, какое именно хранилище они имеют в виду. Сначала я дам вам быструю справочную таблицу, а затем пройдусь по тем частям, которые требуют больше одной строки.

Изображение сгенерировано с помощью ИИ

Быстрая справочная таблица

Вот краткая версия. Если вы знаете инструмент Vue, здесь указан эквивалент из React, с которым вы с наибольшей вероятностью столкнетесь.

Ни одно из этих соответствий не является точным на 100%, а некоторые рассыпаются при ближайшем рассмотрении. Давайте пройдемся по тем, которые действительно важны.

Маршрутизация (Routing)

Vue Router — единственный очевидный выбор во Vue. В React нет одного очевидного выбора; их два сильных, и с каким именно вы столкнетесь, зависит от команды.

React Router — это ветеран и с большим отрывом самый популярный вариант. Если вы использовали Vue Router, концепции переносятся напрямую. Вы определяете маршруты, у вас есть ссылки, вы читаете параметры маршрута, вы делаете вложенные макеты. Имена отличаются, но модель та же самая. Вложенные макеты работают так, как вы и ожидаете. Вы оборачиваете дочерние маршруты внутрь родительского маршрута, который рендерит общую оболочку, например боковую панель или шапку, что совпадает с идеей вложенных маршрутов, которую вы уже настраивали в Vue Router.

TanStack Router — более новый вариант, и его главное преимущество — безопасность типов (type safety). Ваши маршруты, параметры и параметры поиска полностью типизированы, поэтому неверная ссылка приведет к ошибке типов, а не к сломанной странице во время выполнения. Если ваша команда сильно заботится о TypeScript, возможно, они выбрали именно его.

Для маршрутизации на основе файлов (file-based routing) во Vue ответом обычно является Nuxt. В экосистеме React эту роль выполняет полноценный фреймворк, чаще всего Next.js, а также React Router в режиме фреймворка (преемник Remix, который влился в него) — это второе имя, которое вы услышите. Структура вашей папки становится вашими маршрутами, та же идея, которую вы знаете по директории pages в Nuxt.

Стиль router.vue во Vue выглядит так:

routes.js

А структура React Router достаточно близка, чтобы вы сразу ее узнали:

routes.jsx

Обратите внимание, что единственное реальное изменение — это component: UserProfile, превратившийся в element: <UserProfile />. React требует именно элемент, а не просто компонент, потому что все является JSX.

Повседневные элементы тоже совпадают. <router-link> во Vue превращается в <Link> в React Router. Чтение параметров текущего маршрута с помощью useRoute становится useParams. А для навигации из кода, где Vue дает вам router.push, React Router дает useNavigate. Другие названия, но это тот же небольшой набор инструментов, к которому вы тянетесь каждый день.

Клиентское состояние: кузены Pinia

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

Zustand — это то, что покажется вам наиболее похожим на Pinia. Вы определяете хранилище, помещаете в него состояние и действия (actions) и читаете его из любого компонента с помощью хука. Оно маленькое, требует минимум церемоний, и на практике это то, к чему я обращаюсь, когда мне нужен опыт работы с Pinia в React. Если вам нравилась Pinia, начните отсюда.

Redux Toolkit — более тяжеловесный, структурированный вариант, который встречается повсеместно в старых и крупных кодовых базах. Он требует больше настройки, срезов (slices), редюсеров и экшенов в обмен на строгое, предсказуемое изменение состояния и очень хорошие инструменты разработчика (devtools). Это больший объем инфраструктуры, чем просит от вас Pinia. Не позволяйте шаблонному коду (boilerplate) пугать вас, но будьте готовы к его избытку. В большом приложении эта структура является скорее преимуществом, чем бременем, потому что она делает каждое изменение состояния легким для отслеживания спустя месяцы, когда вы уже давно забудете, как на самом деле работает экран.

Вот структура крошечного хранилища Zustand рядом с хранилищем Pinia, чтобы вы могли увидеть семейное сходство.

counter.js (Pinia)

counter.js (Zustand)

Давайте разберем это. Оба предоставляют хук useCounter, который может вызвать любой компонент. Оба хранят count и метод increment. Главное отличие заключается в том, что Zustand выдает вам функцию set для обновления состояния (вы заменяете, а не мутируете — то же правило, что мы видели в Части 2), в то время как Pinia позволяет мутировать this.count напрямую. Синтаксис разный, задача та же.

Еще один вариант, о котором стоит упомянуть. Для небольшого приложения вам вообще может не понадобиться выделенное хранилище. Context плюс useState могут переносить простое общее состояние, точно так же, как вы могли бы пропустить Pinia в небольшом приложении Vue и положиться на composable. Обращайтесь к Zustand или Redux Toolkit, когда состояние вырастает настолько, чтобы этого заслуживать, но не раньше.

Однако важное предостережение. Прежде чем тянуться к какому-либо клиентскому хранилищу в React, спросите себя, является ли эти данные вообще клиентским состоянием. Что подводит нас к самой радостной части всей этой статьи.

Серверное состояние: вы это уже знаете

Вот хорошая новость, которая положит конец всем хорошим новостям. TanStack Query — это та же самая библиотека с обеих сторон. Версия для Vue называется @tanstack/vue-query, а версия для React — @tanstack/react-query, и они разделяют одно ядро и одни и те же идеи. Если вы читали мои предыдущие статьи о TanStack Query для Vue, вы уже знаете и версию для React.

useQuery и useMutation сопоставляются практически один к одному. Единственная реальная разница, которую вы почувствуете, — это особенность Vue, которую вы уже обходили: Vue передает реактивные рефы, а React передает обычные значения.

users.vue

users.jsx

Обратите внимание, что они практически идентичны. Тот же queryKey, тот же queryFn, те же возвращаемые данные и isPending. Это проще всего перенести, так что опирайтесь на это. Когда люди в команде React спорят о том, где хранить серверные данные, ответ обычно такой же, как во Vue: храните их в TanStack Query, а не в клиентском хранилище.

useMutation переносится точно так же, как и привычка вызывать queryClient.invalidateQueries после изменений для повторного получения свежих данных. Если вы усвоили этот паттерн во Vue, он уже есть у вас и в React. Здесь нечему учиться заново, просто другой путь импорта.

Формы и валидация

Мы посвятили всю Часть 4 формам, так что здесь будет лишь упоминание экосистемы. Во Vue вы используете VeeValidate. В React популярным выбором является React Hook Form, очень часто в паре с Zod для валидации схем. Ментальная модель близка к VeeValidate со схемой, так что вы не почувствуете себя потерянным.

Куда вписывается React 19? Встроенные действия форм (Actions) и useActionState из Части 4 самостоятельно обрабатывают отправку и состояние ожидания (pending). Для небольшой формы вам может вообще не понадобиться библиотека. Для большой формы со множеством правил комбинация React Hook Form и Zod — это то, что вы будете видеть чаще всего, и она отлично уживается с возможностями форм React 19.

Одна полезная деталь. React Hook Form опирается на неконтролируемые инпуты для достижения высокой скорости, считывая значения через рефы, а не отслеживая каждое нажатие клавиши в состоянии. Это естественным образом сочетается с идеей «позволить форме самой передавать вам свои значения» из Части 4, поэтому оба подхода отлично дополняют друг друга, а не противоречат.

Мелочи: сборная солянка

У ряда возможностей Vue есть быстрые аналоги в React, которые не требуют отдельного раздела.

  • computed превращается в useMemo. И то, и другое возвращает значение, вычисленное на основе других значений, которое пересчитывается при изменении зависимостей. Загвоздка в том, что Vue отслеживает зависимости за вас, в то время как useMemo требует массива зависимостей — того же ручного списка, с которым вы познакомились для useEffect в Части 2. Еще одно честное замечание. В React useMemo — это оптимизация, а не требование, поэтому множество производных значений просто пишется прямо «на лету» без него. В React также есть более новый встроенный компилятор, который может добавлять такого рода мемоизацию автоматически, так что со временем вы будете использовать useMemo вручную еще реже.
  • provide / inject становится Context. Вы создаете контекст, оборачиваете часть дерева в его провайдер и считываете его с помощью useContext (или хука use из Части 3). Та же идея передачи значения вниз без протаскивания пропсов через каждый слой.
  • <Teleport> превращается в createPortal. И то, и другое позволяет поместить дочерний элемент совершенно в другое место DOM-дерева, что как раз необходимо для модальных окон и всплывающих уведомлений, когда overflow или z-index родителя в противном случае ограничили бы их.
  • defineModel становится пропсом значения плюс обработчиком изменения. В React нет v-model для компонентов, поэтому компонент с двусторонним связыванием принимает значение и onChange — точно такой же паттерн контролируемого компонента из Части 4, просто переданный через границу компонента.

И наконец, давайте быстро рассмотрим пробелы.

  • <KeepAlive> не имеет встроенного эквивалента в React. Нет готового к использованию способа сохранить компонент живым и кэшированным после его размонтирования. Обычное решение заключается в поднятии состояния (lifting state up) к родителю, который остается смонтированным, чтобы данные сохранялись даже тогда, когда дочерний элемент появляется и исчезает.
  • <Transition> также не имеет встроенного ответа. Vue поставляется с анимациями появления и исчезновения «из коробки». В React вы используете CSS самостоятельно или подключаете библиотеку вроде Motion. Это не хуже, просто это не входит в комплект.

Заключение

В этой серии мы прошли путь от первой ментальной перестройки при переходе с Vue на React (что компонент — это просто функция) и вплоть до экосистемы, в которой вам действительно предстоит работать. Если вы вынесете из этой финальной части хотя бы одну мысль, пусть она будет такой. Большая часть ваших знаний Vue переносится, самое сложное — выучить новые названия, и теперь у вас есть этот список.

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

Спасибо, что дочитали до самого конца! А теперь идите и создайте что-нибудь крутое.

О чём эта статья

Ещё в разделе «Разработка ПО»

Все →

Ещё от Telerik