YAM#1: когда хочется написать свою Redux middleware
В своих статьях я собираюсь рассмотреть процесс эволюции ещё одной мидлвари для Redux, которая отвечает за сайд-эффекты.
1К открытий1К показов
В своих статьях я собираюсь рассмотреть процесс эволюции ещё одной мидлвари для Redux
, которая отвечает за сайд-эффекты. Едва ли её можно назвать идеальной, но она точно выстрадана и испытана на передовой. И, пока ребята, поддерживающие Redux
, так и не решили, какая мидлварь лучше, я попробую описать здесь свои мысли и предпочтения на этот счёт.
Чтобы не пугать никого банальностью присутствующих далее идей, хочу предупредить, что начиналась эта история, когда я был ещё зеленым-презелёным джуном без других фронтендеров на проекте, поэтому некоторые инсайды могут показаться вам странными, даже смешными. Что ж, все мы проходили через это.
Нам нужна нормальная мидлварь!
В один прекрасный солнечный день я наткнулся на неподъёмную для меня проблему.
Приложение наше обеспечивало функциональность поиска для интернет-магазинов. Вот один из стандартных пользовательских сценариев:
- выбери значение на фильтре;
- отправь запрос на сервер;
- отрисуй полученные результаты.
Вполне себе классическая история, для которой, однако, использовался совершенно нестандартный подход. Да, у нас были подключены thunk
и, но в тот момент я даже не знал, что там есть getState
аргумент (угу, всё было настолько печально). Видимо, разработчик, который писал это до меня, тоже не знал. Поэтому у нас была использована волшебная концепция Actor
ов: эта такая расчудесная псевдо-мидлварь, работающая на React
.
Компонент, который подписан на состояние, но render
не возвращает JSX, а вызывает необходимые сайд-эффекты. В общем, смотрелось странно, а реализовано было ещё страннее. И вот с таким очаровательным бэкграундом я начал смотреть, как ещё можно добиться нужного поведения.
Но Гугл всемогущий не ответил мне. В итоге было принято решение попросить помощи у опытного фронта с соседнего проекта. Он внимательно выслушал мои жалобы, сказал «смотри, чё могу», и вместе с ним мы сели писать это.
Да будет store next action!
Первая версия была категорически простой.
На самом деле, сложно, наверное, придумать что-то проще. Дайте мне массив функций, и обработаю я вам всё, что хочется. В том числе, и поиск:
Можно было бы на этом и остановиться, так ведь? И всё-таки нет. Некоторое время попользовавшись этим вариантом, я заметил три вещи, которые можно улучшить.
Упрощение интерфейса
Во-первых, я понял, что не всегда я использую все три аргумента, которые передаю в обработчик. Иногда мне не нужно состояние, иногда мне неважно содержимое действия, а иногда я не хочу ничего диспатчить (просто пишу в localStorage
, например). Но, так как сложно было определить, в каком порядке расположить аргументы для максимально частых юз-кейсов, я просто превратил три аргумента в один:
Вуаля, бери всё, что хочешь, а что не хочешь, не бери. Удобно, правда ведь?
Повышение стабильности
Ещё одна важная вещь, которую я где-то прочитал: обработчики должны быть максимально изолированы и ни в коем случае не должны влиять на работу соседей. Уж не знаю, касалось ли это именно мидлварей, или же просто это была умная мысль, но я понял, что изолированности моей реализации не хватает. А вы уже видите, где?
Правильно, мы вызываем store.getState()
при прогоне для каждого обработчика. И, строго говоря, каждый последующий обработчик получает состояние уже изменённым эффектами от предыдущего. Другими словами, порядок добавления обработчиков имеет значение. И я уже чувствую, как подгорают сидушки программистов, которые пытаются это дебажить. Что ж, давайте исправимся:
Та-дааа! Теперь на каждом dispatch
все обработчики будут получать одно и то же состояние. Где-то внутри было отправлено ещё одно действие? Отлично, там мы тоже прогоним все обработчики, но это будет отдельный цикл со своим состоянием, Джеком Блэком и вообще.
Масштабируем
А теперь представьте, что обработчик должен реагировать на несколько разных действий. Что-ж, можно добавить ещё несколько if
, можно превратить функцию в один большой switch
, но где-то мы это уже видели, так ведь? А хотелось бы написать что-нибудь элегантное, чтобы избавиться от всех этих бесконечных if
ов да switch
ей:
Что ж, если вы хотите бороться с подобной проблемой в редьюсерах, сразу рекомендую обратить внимание на Redux ToolKit, там не только switch-case
лечится. Но так как тут мы всё пишем сами, придётся думать. Хотя думать-то особо нечего: вынь обработчик да вызови.
Заключение
Вот у нас и вышла маленькая, аккуратная, но довольно мощная мидлварь:
И вполне готовая для продакшена, скажу я вам. Но вы не спешите. Во-первых, потому что не стоит бросаться на любую новую библиотеку, которую вы видите. Во-вторых, потому что библиотеку я ещё не завёл (хотя и планирую в ближайшее время). Ну а в-третьих, есть ещё пара интересных и важных моментов, которые можно улучшить. Их мы и обсудим в следующий раз.
1К открытий1К показов