Pull to refresh
Comments 16

Как правильно произвести декомпозицию редьюсеров, то есть создать несколько независимых редьюсеров, которые преобразуют независимые состояния, и затем объединить их в один редьюсер? Если создать несколько редьюсеров через redux-symbiote и объединить их через combineReducers, то возникнет риск коллизии названий типов действий (потому что они не записаны в коде явно).

Спасибо за вопрос. `createSymbiote` имеет третий параметр namespace/options, с помощью которого можно задать префикс для всех экшен-типов сразу.
github.com/sergeysova/redux-symbiote#options

const { actions, reducers } = createSymbiote(
  initialState, symbiotes, 'prefix/namespace'
)
// or
const { actions, reducers } = createSymbiote(
  initialState,
  symbiotes,
  { namespace: 'prefix/namespace' },
)


Некоторые примеры использования symbiote можно посмотреть здесь: github.com/howtocards/frontend/tree/dev/src/features/cards/symbiotes
Мы как-то сделали себе похожий велик на одном проекте на TypeScript. Получилось ну очень похоже:

const initialState: CounterState = {
    current: 0
}

const next = ({ }) => (s: MyState) => ({ ...s, current: s.current + 1 });
const set = (a: { value: number}) => (s: MyState) => ({ ...s, current: s.current + a.value });

const { actionCreators, bindActions, reducer } = buildReducer(
    initialState,
    {
        next,
        set,
    },
    { prefix: "COUNTER" }
);


В отличии от велика из статьи, тут все строго типизировано. Например, типы actionCreator-ов и их параметров выводятся (мы ради этого карировали функции, action => state => state вместо (action, state) => state).

Плюс имена экшнов автоматом строятся, и никаких функций в action-ы не упаковывается. Т.е. в нашем случае actionCreators.set({ value: 10 }) => { type: 'COUNTER_SET', value: 10 }.

Вот тут исходники самой утилитки: gist.github.com/jakobz/ae3e5567e20fff3d66d9e8852a9a655a
Я позволю себе скопипастить сюда свое сообщение из другой темы:
Итак имеем:
— Глобальный стор (обычно все глобальное — плохо, а тут вдруг — хорошо).
— Кучу экшенов где action.type уникален в пределах приложения.
— Кучу action creator-ов c названием, в большинстве случаев, таким же как action.type, записанным в другом регистре.
— reducer-ы — по сути обычный switch case.

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

Вопрос:
Где в этом хозяйстве архитектура, абстракции и изоляции и чем оно координально лучше, чем обычные методы хранилища? ЗЫ: Методы хотя бы можно комбинировать в отличии от словоблудия внутри switch case.
Я так и не нашел ответа на вопрос зачем нужны эти псевдоабстракции.
Спасибо за вопросы.

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

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

Архитектура redux неплохо описана в документации и легко бьется на слои:
— стор отдельно, что и как сделать со стором отдельно,
— представление: глупые компоненты, контейнеры, селекторы данных,
— для перехвата действий и последующего комбинирования действий над стором (и не только), например, redux-saga.

Все это можно легко передавать между проектами и тестировать.

Идеального решения нет, как и ответа на все вопросы.
Вы не подумайте что это была претензия к вам и вашей статье. Сам использовал похожие решения и велосипедил ради интереса. Они вполне жизнеспособны, особенно если учесть, что react/redux — достаточно популярные библиотеки.
Не понятно как на такие действия подписываться в том же redux-saga? У них можно имя получить, через какой-то условный name?
yield takeEvery(actions.open.success.name, loadAdditional)
будет работать?
Тогда ок. А с типизацией в TypeScript или Flow как обстоят дела, не в курсе?
Как вижу подобный код и реализацию — честно, плакать хочется. Ну вот реально вьехать с пол пинка вряд ли получится. Далее все что только можно суем в глобальный стор. Туда жа запихавают логику приложения. Вот попробуйте потом такое приложение оптимизировать. Разбить на слои, где с каждым слоем работала бы команда.

Почему не вынести бизнес логику получения и обработки данных в отдельные слои? Зачем все держать в сторе, если данные нужны только в одном месте? Как сделать что-то не завязываясь на redux?

В большинстве туториалов пишут о том, что это серебряная пуля, вот берем и радость. Как сказал один девелопер у меня в команде — «чувак, ты не понимаешь?! Это же React-way! Надо только так писать, так в мануалах пишут». Над… В общем, на практике, это просто добавляет проблем, нежели профита.

Что делаю у себя в проектах, это в первую очередь разделяю приложение на слои: бизнес логика, API, компоненты, Store.

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

Как видно из описания, нет проблем разделить работы между людьми. Не жестких привязок. В любой момент можно заменить слой на другую технологию, не переписывая все остальное.
Как потом эти бизнес слои связывать вместе используя Flux?
Как это дебажить без вменяемых dev-tools?

redux-symbiote был призван решить только одну проблему: убрать бойлерплейт вокруг экшенов и редюссеров, ни больше, ни меньше.
symbiote — чисто апдейтеры стора, thunk/execute — бизнес-логика, components — отображение данных. Всё тоже самое разделение на слои, только более простое.
Разделять приложение между командами нужно полноценно разделяя приложение на micro-frontends, а не работать всем вместе в огромном монолите.

А вот по поводу качественного разделения: я постепенно перехожу на effector. Где есть и полноценный дебаг и статическое вычисление зависимых сторов, и красивое API, и отстутствие проблемы ромбовидных зависимостей.

Мб потом статью о нём напишу.
А вот по поводу качественного разделения: я постепенно перехожу на effector. Где есть и полноценный дебаг и статическое вычисление зависимых сторов, и красивое API, и отстутствие проблемы ромбовидных зависимостей.

Мб потом статью о нём напишу.


Было бы неплохо
Разбить на слои, где с каждым слоем работала бы команда.

Вообще нет проблем разбить на слои.

В данном случае redux-symbiote позволяет уменьшить количество кода, повысить читабельность и структурировать часть архитектуры redux.

У нас все проекты послойные:
— стор (redux)
— что и как сделать со стором redux-symbiote,
— представление: глупые компоненты, контейнеры (модули), селекторы данных (как раз группируют данные для контейнеров из разных частей стора),
— бизнес логика — redux-saga,
— апи и сервисы с возможностью моков.

Уже проектов 10+ с использованием redux разработано — проблем не возникает.

Абсолютно не понимаю зачем этот холивар глобальный стор vs распределенный. Статья не об этом. Каждый выбирает инструмент по необходимости.
Only those users with full accounts are able to leave comments. Log in, please.