Введение

Всем привет :) Хотел бы рассказать об использовании RTK Query + Redux Toolkit в больших проектах, а также ускорить вашу разработку и добавление новых страничек путем избавления от ненужных дублирований кода.

Если ты frontend-разработчик на react, то думаю вам не впервой сталкиваться с использованием RTK Query вместе с Redux Toolkit. Но даже если это не так, то думаю мне есть что тебе показать новое ;) А если ты ни разу не сталкивался с этой связкой, то возможно после этой статьи задумаешься о её использовании.

Предисловие

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

Установка зависимостей: yarn install. Запуск по команде: yarn dev.

Основные проблемы данной связки библиотек

  • Необходимо постоянно писать лоадеры, которые бы показывали загрузку страницы, а затем отрисовывали бы полученные данные.

  • Иногда хочется получить просто данные из запроса без создания отдельного слайса для страницы, а когда-то наоборот.

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

  • Если необходимы 2 и более запроса, то приходится отдельно прописывать логику и объединять запросы. А если один из них провалится, прописывать логику повторного запроса.

  • При добавлении данных в слайс в методе onQueryStarted, данные просто не успевают попасть в хранилище до отрисовки компонента, который его использует.

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

Спешу вас обрадовать, я эти проблемы решил и причем с минимальным количеством кода, поэтому давайте же перейдем к решению и самому проекту.

Структура проекта

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

Папка Redux
Папка Redux

Полезные для использование хуки и компоненты высшего порядка кладем в соответствующие папки hooks и hoc.

Папки hooks и hoc
Папки hooks и hoc

Страницы в Next.js находятся в особенной папке pages. Все примеры использования в cat-facts/index.tsx

Папка pages
Папка pages

Проблема и решение

При добавлении данных в слайс в методе onQueryStarted, данные просто не успевают попасть в хранилище до отрисовки компонента, который его использует.

Переопределяем baseQuery и принимаем через аргументы метод onSuccess, который позволит нам помещать данные в хранилище, а после этого завершать загрузку. Не забываем вызов обернуть в try catch, чтобы видеть ошибки в консоли.

Код

Пример использования слайсов и апи методов
Слайс
Слайс
Api
Api

Необходимо постоянно писать лоадеры, которые бы показывали загрузку страницы, а затем отрисовывали бы полученные данные.

Создаем специальный «хок», который будет делать запросы и выводить сообщения в случае ошибки. Логика его достаточна сложна, поэтому обратитесь к коду проекта. Находится в одноименной папке src/hoc. Можете адаптировать его под свою архитектуру проекта.

Для тех кто разбирается в TS

Типизация при использовании работает отлично, однако от костыля при преобразовании к any, я так и не смог избавиться. Если кто-то знает, как решить, прошу Merge Request в репозиторий кинуть.

Костыль
Костыль

Папка hoc
Папка hoc

Если необходимы 2 и более запроса, то приходится отдельно прописывать логику и объединять запросы. А если один из них провалится, прописывать логику повторного запроса.

Прежде чем использовать метод, создаем страничку, которая будет отрисовывать данные. Чтобы использовать данные от запросов, объединяем типы наших резолверов и наследуемся от них.

Страница отрисовки данных
Страница отрисовки данных

Далее используем «хоки» для обработки запросов к api:

Использовать «хоков»
Использовать «хоков»

withQueryResolver – содержит в себе самый главный запрос, который потом можно принять через аргументы и использовать данные. Вызывать можно только 1 раз и перед withOtherQueryResolver

withOtherQueryResolver – содержит в себе второстепенный запрос, которые нельзя принять через аргументы. Обычно используется, чтобы какие-то дополнительные данные положить в хранилище (слайсы). Должен идти после withQueryResolver. Могут быть вызваны друг за другом несколько раз. При ошибке перезагрузка данных будет только у тех, что завершились ошибкой, а не у всех сразу.

withMutationResolver – отвечает за обработку мутации, показа модалки загруузки, вывод модалки с ошибкой (если нужно). Можно адаптировать под свой проект.

Как мы видим процесс загрузки и объединения запросов занимает всего 2 строчки, а подключение логики с обработкой мутации всего 1 строчку.

И наконец прописываем страницу, которая будет экспортироваться во внешку:

Все аргументы объединяются для каждого хука, поэтому можно избежать дублирования.

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

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

Метод showRetryModal используем, если хотим при ошибке показать модалку, что запрос не прошел и предложить повторить запрос.

Итог

При таком подходе удается создать в проекте устойчивую к росту архитектуру и облегчить разработку. Давайте посмотрим, чего мы добились:

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

  • В случаем изменении какого-то api метода, «хоки» начнут ругаться, что им передали контроллер, который принимает совсем другие данные, нежели те, что api-хук. А значит вероятность выпустить релиз с багами уменьшается в разы, ведь в production такое не скомпилируется.

  • Благодаря объединению аргументов их можно использовать, как в компоненте приемнике, так и в других методах api. Например, миграция одного аргумента метода к другому методу это дело 3 секунд. Добавление какого-то нового аргумента тоже менее болезненна, ведь если он передается для какого-то другого api метода, правки не нужны и typescript не будет ругаться.

  • Если нам достаточно данных из хука, мы можем не создавать отдельный слайс под данные и соответственно не писать лишнего кода. Например, если наша страница всего лишь отображает данные, зачем писать для этого отдельный слайс? Можно просто взять готовые данные и отобразить.

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

Комментарии (3)


  1. Ionenice
    19.06.2022 18:56

    Хотел бы рассказать об использовании RTK Query + Redux Toolkit в больших проектах

    От статьи в 2022 про redux toolkit, rtk и ts хотелось бы видеть сильно больше, чем скрины кода и ссылку на гитхаб. Интересно читать про то, как писать правильные костыли в этой связке или как максимально их избегать. Или под «большими проектами» изначально подразумевались проекты с множеством однотипных страниц где всё что нужно это очередной запрос и его loader?


    1. AleksanderZverev Автор
      19.06.2022 19:10

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

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


      1. Ionenice
        19.06.2022 19:19

        Возможно стоило чуть больше акцентировать внимание, что это стартер, но это ваша статья)

        Просто начав изучать rtk, redux + в связке с ts я столкнулся с кучей проблем, недопонимания, из-за чего пришлось изучать костыли, которые люди предлагают для тех или иных задач. Возможно, каких-то сложных решений мне и хотелось видеть в статьях про rtk