[Из песочницы] Как уменьшить количество и увеличить читаемость кода в react-redux, redux-saga

В этой статье я хотел бы поделиться своим опытом использования связки react-redux и redux-saga, а точнее, какой «велосипед» я использую, для уменьшения количества однотипного кода и упрощению его восприятия.

Что меня не устраивало


Библиотеки react-redux и redux-saga просты, гибки и удобны, однако имеют избыточность кода. Основные элементы это:

  1. Фабрики событий


    lnvf8zygpsql5tynv-je4bgnih8.png

    В таком виде меня смущает несколько вещей:

    — описание типов событий. В этом примере можно конечно обойтись и без констант, но все равно придется передавать его тип в фабрику, которое будет идентично имени созданного события в верблюжей (camelCase) нотификации.

    — если вы забыли структуру пайлоада (payload), что бы его вспомнить, надо перейти к reducer/saga, где используется это событие, и посмотреть что там нужно передавать

  2. Редьюсеры


    1x7sajm9am79qps_lwz0st_1hlq.png

    Тут в целом напрягает только использование конструкции switch

  3. Саги


    z0cegra6wsxuxnv9thgra6xgq90.png

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

    empz7fb_uzvutbrc-pgzc5bcbps.png

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


Как я пытаюсь решить эти проблемы


Давайте по порядку.

  1. Фабрики событий


    cvpe8fpukc4ygzg3aziymzmbvwu.png

    создаем класс с аннотацией actionsCreator (). При создании экземпляра класса, полям не имеющим значения (initialize;/onFieldChange;/handleField;/gpToNextStep; ) будет присвоен привычный нам action creator. Если событие содержит данные, имена полей передаем через аннотацию payload (…[fieldNames]). После преобразования предыдущий пример будет выглядеть вот так:

    c7_nx5payinedrjnc9pq6n-w7-g.png

    так же у полей будут переопределены методы toString, toPrimitive, valueOf. Они будут возвращать строковое представление типа события:

    mqgzwv_c4lap_bbojz3vtc-j3yo.png

  2. Редьюсеры


    eu56e6s-km9pxng8a6fcxvbzzig.png

    создаем класс с аннотацией reducer ([initialState]). При создании экземпляра класса, на выходе получится функция принимающая состояние и экшен, и возвращающая результат обработки экшена.

    3zucfbkgdjdo1vkmpemnzhdkbja.png

  3. Саги


    cydrdl_h-ulcaqegbzekxvzanvs.png

    создаем класс с аннотацией sagas (). При создании экземпляра класса получаем генератор функций, вызывающий все поля класс помеченных аннотацией takeEvery ([…[actionTypes]]) или takeLatest ([…[actionTypes]]) в отдельном потоке:

    -320wvur22jcepvfqpd5zyt77_u.png

    так же с полями можно использовать аннотацию filterActions ({ state, type, payload }), в этом случае сага будут вызвана только если функция вернет true.


Заключение


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

Эти аннотация я вынес в пакет sweet-redux-saga. Если есть другие решения, буду рад, если поделитесь со мной.

© Habrahabr.ru