Pull to refresh

Comments 33

Стоит заметить Мы убрали константы.

Ну константы в `actions` у вас никуда не делись.

Плюс, данный подход просто переложил проблему из одного места в другое. Вместо того что бы иметь большой `switch` с обработчиками в файле `reducer`, вы будете иметь уйму обработчиков в файле `actions`, в последствие, по мере разрастания проекта, по-прежнему придется пользоваться тем же поиском.

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

Ну будет как у вас с редусерами… Просто множество actions.
Так что тут +-
Про константы поправил. Спасибо. Была опечатка.

Наблюдая выше в примере редьюсера комбинированное использование как Object.assign так и спред оператора, подозреваю что и остальная часть проекта страдает от подобной неконсистентности, которая и вызывает вашу так называемую "боль"

Пример с Object.assign взят из оф доки по redux
Вот вот. И вообще лучше использовать спред оператор, тк Object.assign с TypeScript не очень хорошо дружит (можно легко неконтролируемых дел натворить).
поиск — нужно все время нажимать Ctrl + F причем глобально Ctrl + Shift + F
Используйте TypeScript.
не видно сразу от куда ноги растут. Вытекает из пункта выше.
Используйте TypeScript.
нет, это всего мало, так у меня еще весь проект пронизывают константы. Нет я не против констант но зачем? Тем более если их использовать вместе с вложенностью как в примере да если еще их конкатенировать из нескольких то это вообще ад навигации.
Используйте github.com/pelotom/unionize.
логика размазана. В одном месте действия в другом обработка этих действий в третьем (опционально) константы которые нужны только тем двум.
Используйте github.com/pelotom/unionize.
Вот ради этого мы вынесли логику отвечающую за передачу данных стору. Reducer остался обеспечивать работу всего механизма. И он должен делать это хорошо не отвлекаясь на вещи его не касающиеся. А нам остается только наблюдать порядок в том от куда растут ноги и если надо то быстро найти и исправить или дополнить.
Очень недальновидно прилепить реализацию ридьюсеров к экшенам:
— В приложении может быть много разных ридьюсеров на тот же самый тип экшена. Допустим я послал экшен из модуля1, а модуль2 и модуль4 будут по-своему его обрабатывать собственными ридьюсерами, плюс lazy модуль5 когда загрузится тоже начнет этот экшен обрабатывать. Пример утрирован, но что-то такое может существовать. Исходите из посыла что экшен это событие с пейлоадом, а ридьюсер это обработчик события. Вы ведь не станете спорить что у события может быть сколько угодно разных обработчиков.
— Представьте себе что у вас больше SPA со множеством lazy/ленивых модулей. Любой экшен может быть послан из любого модуля при этом сами экшены очень легковесны. То есть это не так страшно импортировать допустим все экшены или по отдельности в каждый модуль (особенно если это константы, а не бандлы тк tree shaking). Но вы привязали сам обработчик к экшену и в итоге все модули загрузят и всю логику ридьюсеров тоже что не является желательным поведением приложения.
— Я бы еще причин придумал, но написанного считаю уже достаточно.
Вот у вас есть state. Большой, развесистый, с кучей комбинированных редюсеров. У вас или будет 2 куска обработки одного события в разных файлах с разными редюсерами, и потом из результатов их работы будет собираться единый стейт, или же будет один метод, в котором будет описано полное преобразование стейта в одной функции. В redux традиционный подход с switch-case — просто неплохо работающий вариант. Требование к его реализации только одно — newState = reducer(oldState, action). А внутри можно и к dom обращаться, и к сети, и 3d рисовать. Хоть и не стоит.

В традиционной реализации redux есть проблема. И если многие считают проблемой большое количество бойлерплейта и констант, то я считаю проблемой линейную сложность редюсеров от количества экшнов. Если у тебя есть 500 разных типов action, то store.dispatch каждый раз будет делать 500 сравнений ссылок на строку action type

А «Используйте TypeScript» это глупый максимализм. Несмотря на мои определенные к нему симпании, typescript и javascript — разные языки программирования. Вы ведь не приходите в посты про python и не говорите там «Используйте C#»?
то я считаю проблемой линейную сложность редюсеров от количества экшнов.
Проблема скорее не в количестве а как часто экшены летают. Оптимизировать резолвинг ридьюсера по типу экшена всегда можно.
А «Используйте TypeScript» это глупый максимализм.
Это насущная необходимость при разработке решений сложнее hello world, просто не все это еще осознали.
typescript и javascript — разные языки программирования.
Это не так, в рантайме они абсолютно идентичны.
Вы ведь не приходите в посты про python и не говорите там «Используйте C#»?
А вот как раз python и C# совсем разные.

Кажется у нас появилась новая религия. Свидетели TypeScript-а :)

Каждому свое. Мне эту штуку никто не назязывал и выбор был не спонтанным, сначала попробовал некоторое время.
UFO just landed and posted this here

Это не очень сильно отличается от предложенного в статье, как мне кажется :)

UFO just landed and posted this here

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

Меня тоже всегда убивало это месиво из switch-case
Решение классное, простое и грамотное. Но в традиционном стиле redux его бы надо было написать как middleware
Что-то в виде:
const functionalReducerMiddleware = store => next => action => {
    if (action.func) return action.func(next)
    else return next
}

Хотя вообще я бы если интегрировал такое решение, как-то гарантировал бы, что action.type у таких штук будет уникальный и больше нигде не используемый, чтобы ни у кого не пришло в голову обработать такой экшн ещё и в редюсере
Меня тоже всегда убивало это месиво из switch-case

Для меня одна из загадок вселенной состоит в том, на кой чёрт все пишут эти switch-case-ы? Кто мешает выносить каждый case в отдельный метод а оркестрировать их по action.type + hashMap. Собственно когда мы декомпозируем обыкновенный код — мы же не пишем повсюду switch-case-ы. Они ж уродливы.


Народ посмотрел документацию на redux и пошёл копипастить.

Народ посмотрел документацию на redux и пошёл копипастить.
Кто-то еще спорит что большая часть JS пользователей не скрипт кидди.

Подход интересный, но константы всё-равно нужны. Экшены же как-то надо диспэтчить.

Я правильно понимаю, что unionize рушит все вкусности на уровне import-export-а? Т.е. мы работаем не точечно с конкретным actionCreator-ом, когда импортируем что-то, а тащим весь список экшнов и на месте используем нужное? Если да, то я бы не стал такое применять в деле на проектах без TypeScript-а. Мне кажется выгода графа зависимостей превалирует над таким подходом.

Экшены это очень легковесные штуки, будь то константы или бандл констант. Да unionize проявляет себя лучшим образом именно при использовании TypeScript. Сама библиотека совсем легковесная и грузится один раз в vendor бандле, а бандлы экшенов тоже не тяделые совсем. Именно бандлы, логическое деление, тк пихать все в один бандл и потом его везде импортировать было бы неразумно.

Я имел ввиду граф зависимостей а не "вес" кода. В случае TS я могу не переживать, что использую ключ action-а, которого нет. В случае JS такую возможность предоставляет простой import конкретного action-а (что кажется вообще не про unionize). Дальше дело за линтерами.

Очевидно это так. Но те кто до сих пор работают с чистым JS ведь согласны все держать в голове, это их путь и ничего нового или неожиданного здесь нет.

Ну собственно отдельно лежащие action-type от которых у всех так бомбит — это ведь как раз попытка Дена Абрамса не держать это в голове. Своего рода типизация через import-export-ы )
Я смотрю в экосистеме React в целом любят делать "типы" на JS руками.

Это полумера тк в масшате всего приложения редакс экшены это небольшая доля кода. К томе же это добавляет бойлерплейта.

Есть 1 интересное решение с константами, которое я задействовал в одном из своих проектов. Опишу только суть:


// action creators
export const aOpen = new ActionBuider('id');
export const aSave = new AsyncActionBuilder(['id', 'data'], asyncHandler);

// reducers 
const handlers = 
{
 [aOpen]: (st, action, rootSt) => { ... },
 [aSave]: (st, action, rootSt) => { ... },
};

// somewhere
connect(
 mapStateToProps,
 { open: aOpen }
)(SomeComponent)

Может возникнуть вопрос — а где вообще типы? а вот они: aOpen, aSave. Самописный babel-plugin просто меняет new ActionBuilder(...).setType('OPEN');. Если его не подключить, то будет просто уникальный ID аля "id1231". Если подключить — обыкновенные привычные типы. Ну и систему префиксов вдобавок (в примере не стал пудрить мозг с ними)

Мне пока что сложно представить как повлияет такое нововведение на реальный проект. Пользуясь случаем хочу дать ссылку на интересное предложение которое я например уже точно использую и которое кажется облегчает разработку github.com/erikras/ducks-modular-redux
UFO just landed and posted this here
UFO just landed and posted this here

При вашем подходе экшны более не сериализуемы. Т.е. вам более не смогут прислать пачку экшнов с продавцом, вы у себя сделаете риплей и восстановите стейт.
Второй момент: мне не очень понятно как с таким подходом вы разбиваете стейт на более маленькие кусочки. Учитывая, что вы предлагаете выкинуть combineReducers, получается каждый экшн должен обрабатывать весь стейт целиком?

Sign up to leave a comment.

Articles