Pull to refresh

Comments 113

Вы уж простите, но выглядит как очередная истерика.

Сравнения с первым ангуляром вызывают сомнения.
Одной фразой «написали бизнес-логику»? А как же отдельные файлы под сервисы, под модули, связать это все потом?
Редьюсеры, экшены и мидлвари для компонентов? Ну так не пишите, это то же самое «написали бизнес-логику», только гранулярно и в разных файлах. Не нравится — пишите прямо в компоненте. Вся асинхронщина прекрасно кикается в componentWillUnmount.

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

Возможно пора двигаться дальше, посмотреть как все эти проблемы решали до нас более зрелые стеки?
Так и решали: redux это пародия на CQRS+ES, прекрасно применяемые в огромных приложениях. А в качестве process-managers выступают саги.

Будущее

Компоненты контейнеры
Контейнеры — не компоненты с бизнес-логикой, а CQRS-обертка.
Selectors — ORM. И да, нам нужны не только getters но и setters;
Нет, не так. Селекторы/геттеры — cQrs, экшены/сеттеры — Cqrs.

Нам нужен стандарт, но уже не “frontend”, а Универсального Приложения, работающего везде, от унитаза, до космического корабля?
Но ведь и так уже все работает же?
Да, Вы абсолютно правы, это моя истерика, не более того.

Лол, а я как раз подумываю написать статью, что redux это счастье. Видимо мое удовольствие от работы === удовольствию Дена и === отсутствию магии.


Для меня крутость redux в детерменированности и декларативности.


Декларативность (в очень вольном толковании смысла этого слова) — в отличие от "дергания" каких-то функций и методов с какими-то побочными эффектами, redux дает простую кнопку "отправить action".


То есть на предыдущих фреймворках или вашем любимом jquery вы писали методы, за которые потом "дергали" и старались все это дело как-то упорядочить, то в redux эта структурированность из коробки. Всю побочку вы описываете в middleware или action creator'ах. Вся работа с данными приложения — ТОЛЬКО через reducer'ы. (А ваше желание "setter"ов демонстрирует полное непонимание самой идеи redux)


Я не беспокоюсь что что-то сломается когда я делаю dispatch(action), в отличие от, скажем, вызова метода сервиса ангуляра. Потому что самого сервиса больше нет и вся обработка бизнес логики структурированно находится в одном месте, а не размазана по куче этихъ самых сервисов.


И детерменированность — В каждый конкретный момент времени я знаю что именно повлияло на мои данные. Никаких "а вон в той не очень хорошо написанной директиве сработал $scope.$on() и что-то поменял в модели". No way. Более того, кроме этого осознания, я ещё и правда могу удобно посмотреть и отследить все действия, которые и привели к данному состоянию модели.


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




А если это был просто истеричный инфоповод для идеи вашего Универсального Приложения — то, пожалуйста, посмотрите сюда: http://xkcd.ru/927/

В чём-то с Вами согласен, вот особено с этим — http://xkcd.ru/927/.
К сожалению, не разделяю Вашего оптимизма по поводу redux, единственный и самый важный для меня фактор, это просто, а следовательно скорость разработки решения. С redux это увы не так.

Вопрос, если Вас не затруднит, используете ли Вы придуманные авторами redux способы или используете сторонние решения для:
создания action'ов?
создания actionCreater'ов?
создания бизнес логики?
Как Вы получаете данные из состояния?

Как Вы думаете, чем отличается «событийная система» redux, от скажем EventEmitter, чем она лучше?
Смотрели ли Вы на MobX?

Вы говорите "скорость разработки", а указываете на скорость setup'а.


Почему в вашей табличке, например, указаны middlewares? Вы что, часто пишете middleware для компонентов? И почему "зарегистрировать reducer" это не "подключить компонент"? Почему у вас в angular 1 не указано какие файлы надо создать? Вы прям в одном файле пишете и шаблон и контроллер и модель и бизнес-логику?


Что значит "связать actions, reducers с компонентом?" Сделать импорт action creator'ов?


А в первом ангуляре вам не надо файлы импортировать и делать app.directive('abc', ['123']) ?


Это первое. И второе:


Почему вы разделяете написание action'ов, reducer'ов с бизнес-логикой? Где вы пишете бизнес-логику если не в redux?


Action'ы и reducer'ы это и есть бизнес-логика.


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


Как Вы думаете, чем отличается «событийная система» redux, от скажем EventEmitter,

В redux односторонний, централизованный и единый поток. Если я отправляю action, я 100% уверен что оно ЛИБО отправило другие действия, ЛИБО изменило что-то в store.


Всё. Больше нет вариантов.


Я могу включить дебажный middleware и посмотреть какие именно действия отправило данное действие.


Если я отправляю событие в EventEmitter, где мне потом собирать обработчики данного события? Как мне посмотреть кто и как обработал событие?


Сделать единый EventEmitter с интерфейсом для middleware и четким разделением "это событие меняет данные" / "это событие отправляет другие события"? Ну дык это и есть redux.


На mobx не смотрел, но судя по страничке они сделали что-то типа того же redux, только с декораторами и обернули селекторы в observable.


единственный и самый важный для меня фактор, это просто, а следовательно скорость разработки решения

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


Если вы не поддерживаете проекты больше месяца и хотите ляпать по SPA в неделю, то тогда да, redux не для вас. Только тогда не надо истерить на всех, ок?

> Если я отправляю action, я 100% уверен что оно ЛИБО отправило другие действия, ЛИБО изменило что-то в store.

А вот и неправда. Отправка action'а приводит к любым последствиям, в зависимости от того, что у вас стоит в middleware (и, с-но, к любым абсолютно сайд-эффектам). Оно вам хоть ракету запустит, асинхронно, фоном. Предсказуемости, конечно же, нету никакой — т.к. раз экшоны в middleware обрабатываются асинхронно (и асинхронно спавнят другие экшоны), то порядок их спавна и обработки недетерменирован. То есть, в зависимости от удачи, исполнение одного и того же экшона может приводить к разным результатам.

> Если вы не поддерживаете проекты больше месяца и хотите ляпать по SPA в неделю, то тогда да, redux не для вас.

Вы явно никогда не видели проекта, в котором количество экшонов на одной странице измерялось бы сотнями. В этом случае обычно извращаются кто как — вплоть до прикладывания к коду схем КА, потому что из самого кода, в силу redux'овской бессвязаности, понять ничего нельзя в принципе.
У нас в проекте один и тот же экшен может обрабатываться 2-3 разными редьюсерами. Очень раздражает такое дебажить.

Ну middleware-то посмотреть не проблема. Понятно что без знания проекта уверенности быть не может.


Суть такая что все сайд эффекты локализованы в action-creator'ах и middleware. Это дает значительно больше уверенности, нежели когда сайд-эффекты размазаны по структуре сервисов (в том же angular). И ракету оно запустить может, да, но вот данные поменять в store — нет. увы. Может выслать другой экшн, но напрямую поменять — нет.


Предсказуемости, конечно же, нету никакой — т.к. раз экшоны в middleware обрабатываются асинхронно

А promise или observable возвращать не?


Можете привести пример экшона который отправляет кучу асинхронных экшонов и не может вернуть промис когда всё основное закончилось?

> Ну middleware-то посмотреть не проблема.

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

> Суть такая что все сайд эффекты локализованы в action-creator'ах и middleware. Это дает значительно больше уверенности, нежели когда сайд-эффекты размазаны по структуре сервисов

Чем размазывание по сервисам отличается от размазывания по асинхронным экшонам? Там разница в коде — минимальная и чисто синтаксическая.

> А promise или observable возвращать не?

Возвращать, извините, откуда? store.dispatch(action) — вот здесь, из dispatch?
Возвращать, извините, откуда? store.dispatch(action) — вот здесь, из dispatch?

Эээ, очень странный вопрос. Откуда ещё-то? Только не говорите, пожалуйста, что вы не знали, что dispatch пробрасывает возвращаемое значение от милварей

Так он же возвращает то, что возвращает middleware. Не понял, как это решит проблему с отсутствием детерменизма в обработке. Вот вам прилетел в стор асинхронный экшон, потом еще один (до того, как зарезолвился первый). Какой из них в итоге первый зарезолвится — неизвестно, и результат будет зависеть от порядка.
Мы же с вами это уже вроде обсуждали. Экшены не должны быть асинхронными, а процесс синхронизации порождаемых ими эффектов описывается в саге.
> Экшены не должны быть асинхронными, а процесс синхронизации порождаемых ими эффектов описывается в саге.

Это никак не отменяет того, что порядок, в котором простые экшоны потом придут к вам в редьюсер, не определен.
А вы и не должны знать этот порядок. Если вы завязываетесь в редьюсере на порядок, у вас неправильный редьюсер.
В редьюсере на порядок завязаться нельзя в принципе, для редьюсера никаких экшонов кроме одного не существует. Речь изначально шла конкретно о том, что когда вы делаете store.dispatch(doAnything()) вместо функционального вызова doAnything(...) — то не надо думать, что вы чудесным образом избавляетесь от классических проблем с управлением стейта. Происходит-то в результате этого вызова одно и то же — грязный вызов грязных эффектов.
экшонов кроме одного не существует
Ну как это. Вся фишка в возможности обрабатывать в одном редьюсере разные экшены.

грязный вызов грязных эффектов.
Вообще-то нет. doAnything() не содержит в себе эффекта, эффект описан в саге как реакция на результат doAnything, который является декларативным описанием, что вообще произошло в приложении. А если у вас внутри doAnything промисы, thunk'и и прочая белиберда, так это значит, что идея redux нарушается.
> Ну как это. Вся фишка в возможности обрабатывать в одном редьюсере разные экшены.

Разные _типы_ экшонов. А сам экшон вы обрабатываете каждый раз один единственный — который к вам прилетел. И про другие вы вообще не в курсе.

> Вообще-то нет. doAnything() не содержит в себе эффекта, эффект описан в саге как реакция на результат doAnything

Давайте начнем с того, что вообще, по дефолту, в редаксе никаких саг нет. И если, например, те же миддлеваре для промисов упоминаются в доках, то саги — не упоминаются.

Надо понимать, что, фактически, саги имеют очень мало общего с редаксом в плане архитектуры — они просто используют миддлеваре-инфраструктуру редакса как базу для интерпретатора своего дсл'я. Интерпретатор (сага-мидлеваре) по одному принимает сага-команды и исполняет их. Заметьте — вы даже можете полностью отказаться от редьюсеров и писать вместо них так же саги (некоторые так и делают). Тогда от редакса ничего кроме лупа интерпретатора внутри dispatch вообще не остается!

> А если у вас внутри doAnything промисы, thunk'и и прочая белиберда, так это значит, что идея redux нарушается.

Ну как это нарушается? С промис-мидлеваре у вас там и будет промис, вот прям самый что ни на есть тупо-промис, обыкновеннейший, чистейший. И это более «дефолтное» для редакса решение, чем саги (которые вообще не стоит рассматривать в контексте архитектуры редакса в силу указанных выше причин).
Разные _типы_ экшонов. А сам экшон вы обрабатываете каждый раз один единственный — который к вам прилетел. И про другие вы вообще не в курсе.
Блин, ну понятное дело. (state, action) => state.

по дефолту, в редаксе никаких саг нет
По дефолту и thunk'ов нет. Все синхронно.

те же миддлеваре для промисов упоминаются в доках, то саги — не упоминаются
Доки

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

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

дефолтное
Вот об этом вообще нигде не слова, с чего вы взяли.

> Доки

Это просто ссылка на все связанные проекты в конце. А про промис-миддлеваре написано прямо в разделе миддлеваре.

> Правильно, потому что редакс идеологически синхронен.

Потому что он не о том. Редакс — про изменение стейта через композабельные редьюсеры, а саги — про декларативное описание эффектов. То, что саги прикручены к редаксу — это вообще исторический казус (там от редакса реально используется десяток строк кода). И у них, насколько я помню, даже issue был на откручивание.

> Промис не чист по определению, мы это уже обсуждали.

«чистейший» в смысле «чисто промис», а не в смысле чистой функции в терминологии фп :)

У вас какой-то особый многопоточный js? Ещё раз сначала: Я сделал dispatch — оно прошло до конца и либо отправило экшоны, либо поменяло данные. Никакой асинхронный экшон за это время не прилетит. ДА, оно может заспавнить асинхронные сайд-эффектовые экшоны. Которые никак не повляют на данные, потому что когда им придет время резолвится, они точно так же отправят простые экшоны в стор. И, если вам важен порядок прихода этих экшонов в стор (что уже подозрительно) — то у вас есть все инструменты чтобы это обработать.


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


const asyncAction0 = () => (dispatch, getState) => {
  dispatch(asyncLoadRocketWithBomb()) // Плохо
  dispatch(asyncLaunchRocket()) // ААА
  dispatch(killAllHumans()) // Асинхронность
  dispatch(asyncProfit()) // Непонятно резолвятся
}

Тут я уже помочь не могу, я пытался.

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

Вы сами себе противоречите. Если асинхронный экшон может отправить в стор обычный — то этот асинхронный экшон МОЖЕТ влиять на данные. Тот факт, что вы делаете это через промежуточный вызов — никак не сказывается вообще на control-flow вашего приложения. Нет никакой разницы между вызовом экшона и вызовом функции, апдейтящей стор напрямую.

Давайте я попробую привести пример.


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


fetch("http://example.com/api/get/some/data")
  .then(r => r.json())
  .then(data => dispatch({ type: DATA_RECEIVED, data: data }))

Какая с таким кодом может быть проблема? А очень простая.


  1. Пользователь делает действие, которое приводит к выполнению этого запроса.
  2. Запрос успевает обработаться сервером, но подвисает из-за сетевого лага.
  3. Пользователь (возможно, другой) делает действие, которое меняет разделяемое состояние на сервере.
  4. Пользователь (первый) повторяет свое действие, запрос на получение данных приходит второй раз.
  5. Приходит ответ на запрос, отправленный на шаге 4.
  6. Приходит ответ на запрос, отправленный на шаге 1.

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

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

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


Понимаете? На самом верхнем уровне будет цепочка экшенов:
DATA_RECEIVED (от шага 4)
DATA_RECEIVED (от шага 1)


Поэтому я и писал, что "уверен 100%" — я отправляю fetchData(), и никакие данные она мне не поменяет потом втихую. Она пошлет экшон на изменение данных.


Redux не дает магическим образом дополнительный функционал, скорее наоборот, в противоположность магии он делает только то, что написано и в этом-то и есть то самое "счастье разрабатывать под redux". Потому как всё под контролем — хочешь дополнительный функционал? Вот возможности. Не хочешь — как хочешь.


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

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

А есть какие-то проблемы в том, чтобы залогировать точно так же обычные функции?

> А если для человека «Нет никакой разницы между вызовом экшона и вызовом функции, апдейтящей стор напрямую.»

Это не для меня ее нет, ее по факту нет. Вы никак не сможете по поведению определить, был ли вызван экшон, или стор обновили «напрямую».

"отловить" = "дописать функционал, например сверяющий время отправки", а не залогиировать, хватит троллить.


Например я могу добавить в интерфейс DATA_RECEIVED параметр "время отправки", а в редусере сравнивать время. Или сделать как в доке и не позволять отправить второй запрос пока идет первый.


Это не для меня ее нет, ее по факту нет. Вы никак не сможете по поведению определить, был ли вызван экшон, или стор обновили «напрямую».

Теперь вы противоречите сами себе. То у вас ужасные, мерзкие асинхронные мидлвари разворачивают поведение экшона на 180°, запускают ракету, то вдруг экшон который проходит через те же самые жуткие мидлвари ничем не отличается от сеттера (которых, кстати, внезапно может быть много, потому что сеттер это дело сервиса, а экшон — дело глобальное)

Например я могу добавить в интерфейс DATA_RECEIVED параметр "время отправки", а в редусере сравнивать время. Или сделать как в доке и не позволять отправить второй запрос пока идет первый.

Ну а я на mobx могу добавить в текущий скоуп параметр "время отправки", а в обработчике его сравнивать. Или не позволять отправить второй запрос. Или отменить первый запрос.


И на knockout я могу сделать так же.


И даже на jquery я могу сделать то же самое. Абсолютно то же самое.


Redux никак не помогает это делать.

И чем же, по-вашему, тихая отправка DATA_RECEIVED отличается от тихого апдейта через сеттер?

Возможно в комментарии выше вы проглядели… СЕТТЕРОВ МОЖЕТ БЫТЬ НЕСКОЛЬКО, так видно?


DATA_RECEIVED отправляется экшн креатором, который имеет определенный интерфейс.


Так вот redux помогает это делать путем явного объявления, так что вам не придется искать где вы там на jquery сныкали setterы. которых, опять же, может быть неско… оу, я уже писал это. А ещё экшен проходит через middleware.


Прямо такой унифицированный интерфейс для доступа к единственному источнику правды.


И даже на jquery я могу сделать то же самое. Абсолютно то же самое.

Как вы из "помогает" вывели "без redux этого никак не сделать"?


Просто пожелаю удачи когда у вас появятся 2 компонента которым нужны эти данные и вы со своим jquery будете писать jquery-сервис, лол

ВЫЗОВОВ dispatch ТОЖЕ МОЖЕТ БЫТЬ НЕСКОЛЬКО


Если вы так не делаете — это потому что вы не разбрасываете грабли в своем же коде для себя самого.


Но точно так же можно и не создавать второй сеттер.


так что вам не придется искать где вы там на jquery сныкали setterы

А зачем мне их ныкать куда-то?


Кстати, если доводить до абсурда — то и в redux редюсер или мидлварь можно так заныкать, что вы его не найдете.


Просто пожелаю удачи когда у вас появятся 2 компонента которым нужны эти данные и вы со своим jquery будете писать jquery-сервис, лол

На самом деле, достаточно двух функций (ну, еще защиту от гонок добавить — но она делается одинаково):


function RequestData() {
    fetch("http://example.com/api/get/some/data")
        .then(r => r.json())
        .then(DataReceived)
}

function DataReceived(data) {
    // ...
}
ВЫЗОВОВ dispatch ТОЖЕ МОЖЕТ БЫТЬ НЕСКОЛЬКО

dispatch (несколько) => action ОДИН => middleware => store


setters (несколько) => store


А зачем мне их ныкать куда-то?

Кстати, если доводить до абсурда — то и в redux редюсер или мидлварь можно так заныкать, что вы его не найдете.

сеттеры вы пишете в отдельной папке setters? или все таки в компонентах/сервисах? вот туда и заныкаете вместе с fetchData. В redux всё по полочкам.


Нет. окей, вы взяли свою (и всех программистов на проекте) волю в кулак и создаете эти сеттеры, кладете их отдельно чтобы вызывать из сервиса, лол, создаете некий объект в который будет класть данные DataReceived, как-то подписываетесь на его изменения.


Теперь добавьте middleware и у вас будет… убогий hand-made redux. Ура!

Вы упускаете из виду тот факт, что обсуждаемый dispatch вызывается по окончанию обработки запроса — а значит, несколько вызовов dispatch означают, что один запрос отправляется из нескольких мест.


Настоящая причинная цепочка выглядит так:


X => fetch => dispatch (несколько) => action => middleware => store
X => fetch => setters (несколько) => store


Ситуация, когда у вас есть два разных X, будет мешать вам разбираться с гонкой независимо от того, используете ли вы dispatch или setters — потому что для борьбы с гонкой вам надо менять не только получение данных, но и отправку запроса, какой бы способ вы не избрали (кроме, пожалуй, серверного времени в ответе — но, допустим, его там не передается, а api менять нельзя).


И в обратную сторону это тоже работает — до тех пор, пока я следую DRY и не делаю один и тот же запрос к серверу из разных мест в коде — у меня нет проблемы с разными сеттерами.

> Так вот redux помогает это делать путем явного объявления, так что вам не придется искать где вы там на jquery сныкали setterы

Это вы о чем? Как раз на сеттер я прыгну по go to definnition, а вот сныканные экшоны мне придется искать.
> Например я могу добавить в интерфейс DATA_RECEIVED параметр «время отправки», а в редусере сравнивать время. Или сделать как в доке и не позволять отправить второй запрос пока идет первый.

Замечательно. Кто мешает все то же самое сделать с обычными функциональными вызовами? Это же достигается одной единственной функцией-оберткой.

> То у вас ужасные, мерзкие асинхронные мидлвари разворачивают поведение экшона на 180°, запускают ракету, то вдруг экшон который проходит через те же самые жуткие мидлвари ничем не отличается от сеттера

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

И чем же, по-вашему, тихая отправка DATA_RECEIVED отличается от тихого апдейта через сеттер?

Ну, строго говоря, то, что диспатч что-то возвращает — это грязный хак. У вас там вообще может быть что угодно, в зависимости от подключенных вообще где-то сбоку мидлварь. Компоненту-то на это наплевать. Так что, если вы разбираете возвращаемое значение, стоит задуматься, может редакс-то и не нужен.
Ну, зная товарища Абрамова, он свое мнение может менять по 5 раз в году. Учитывая, если глянуть на дату этого поста.
К тому же он нарушает one-way-data-flow, который сам же и пропагандирует, так как теперь состояние «асинхронная операция завершена» приходит не через стор.
Еще он нарушает инкапсуляцию экшенов, раскрывая, что внутри диспатча оказывается промис. И то! Только если не забыть вернуть. Так себе решение.
Thunk и Promise мидлвари были введены как простое и быстрое in-place решение но в ущерб идеологии.
> в отличие от «дергания» каких-то функций и методов с какими-то побочными эффектами, redux дает простую кнопку «отправить action».

Но ведь кнопка «отправить action» — это и есть функция с побочными эффектами.
Ваша табличка ну вообще ничего общего не имеет с реальностью. В столбце с Реактом вы показываете как работать с React + Redux, в столбце с AngularJS вы показываете как работать с AngularJS. Я никогда не работал с AngularJS, но в Angular (2+) есть библиотека ngrx, которая представляет из себя что-то вроде Redux, позволяя подключить к приложению глобальный стор. Так вот, чтобы подключить ngrx в Angular, нужно сделать столько же, сколько и в случае с React. Ровно и наоборот, сам по себе React-компонент помещается в одном файле, без actions, constants, reducers, etc…
Боюсь с Вами не соглашусь
Ваша табличка ну вообще ничего общего не имеет с реальностью.
. Количество действи для достижения успеха явно разнится.

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

Ну подождите… Я высказал свое мнение только про табличку. Заголовок называется: создание равнозначных компонентов в 2х стеках: redux/react и angular 1. Если опустить различные best practices и все таки создать равнозначные hello-world компоненты, при этом используя глобальный стор, то количество действий примерно одинаковое.
Извиняюсь за то что ввёл в заблуждение, равнозначность о которой я говорю — это равнозначность функционала, а не равнозначность архитектуры.
Да, я имел ввиду именно архитектуру :)
А говоря про функционал, тут уже зависит от человека, от его опыта, имхо.

Прошу прощения, но с таким же функционалом на каком-нибудь jquery я могу написать прямо в одном файле в index.html в script-тэге, это совсем не показатель.

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

Одно могу сказать от опыта работы с Redux, его долга настраивать и запускать. Но как только вся инфраструктура готова, поддерживать его и добавлять новые фичи одно удовольствие.
Хотя полностью согласен с автором что Frontend в последние годы усложнился в несколько раз, но прирост производительности увы не соответсвует такому же тренду.
А бывало ли у Вас такое, что вместо создания новой цепочки action -> actionCreater -> case in reducer, Вы писали более общий action и универсально его использовали, просто для экономии душевных сил и скорости разработки приложения?

Вероятно, вы не умеете готовить Redux. Пример чтения данных из API в форму и записи из формы в API с валидацией (на выбор варианты redux-saga/redux-thunk), применяя ducks-pattern.

О том и речь, что в чистом виде, работа с redux сложна неэффективна.
Это и является причиной появления надстроек над самим redux, что опять же подчёркивает проблематику.
Пара вопросов, для ответа по желанию:
1. Если инструмент не эффективен, зачем он нужен? Ради себя самого?
2. Как вы пришли к использованию redux? Какие проблемы Вашего приложения он решал?
Мне кажется, что вы делаете ошибочные выводы.
Давайте начнем с начала. Для чего нужен Redux? Для управления состоянием приложения. И надо отметить, что эта задача выполняется очень хорошо. Redux задает четкие правила изменения данных в приложении, вы всегда знаете что именно вызвало изменение состояния. Однонаправленный поток данных, изменение состояние через простые чистые функции, которые легко тестировать. И все это достигается просто из коробки, без дополнительных инструментов. Да, конечно, цена этому некоторый шаблонный код (имена экшенов, экшен-крейторы и т.д.), но это ни «сложно», ни «неэффективно». Скажите, вы действительно на каждый новый компонент создаете новый редюсер, экшен? Не знаю как у вас, но по-моему опыту большая часть компонентов — это глупые компоненты, они просто не требуют тех шагов, что вы описали в своей табличке. Мне кажется, что вы преувеличиваете проблему.

Работа с redux сложна неэффективна. Это и является причиной появления надстроек над самим redux, что опять же подчёркивает проблематику.

А не думаете, что причиной появления надстроек является расширяемость Redux? Redux отлично решает проблемы с управлением синхронными данными, но для сайд-эффектов он не столь удобен. Зато есть API для создание middleware — расширения функционала. Эта возможность породила такие замечательные инструменты как redux-thunk, redux-observable, redux-saga (мой выбор). Причем это порождает конкуренцию, одни инструменты лучше других, и вы утверждаете, что это негативная сторона?
Имхо, redux лучшее решение для менеджмента состояния. Ни reflux, ни mobx, ни angular не давали для меня такой уверенности в работе приложении как это делает redux.

Если инструмент не эффективен, зачем он нужен? Ради себя самого?

ИМХО, вопрос не имеет смысла ибо содержит в себе ложную информацию.
Мне кажется, что вы делаете ошибочные выводы.

Ради этого мой пост и существует, поделиться мнением, возможно дать пищу для ума, возможно узнать для себя что-то новое — изменить мнение.

Управление состояниями, а полноценная база данных не решила бы этот вопрос?
Диспетч событий экшенов, почему бы не использовать шаблон наблюдатель?

А не думаете, что причиной появления надстроек является расширяемость Redux?

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

Но чего у redux не отнять — это middleware, вот они просто супер, хоть и нарушают в текущем виде SOLID.

возможно узнать для себя что-то новое
И это прекрасно!

Управление состояниями, а полноценная база данных не решила бы этот вопрос?
Не решила бы, так подавляющее число баз императивны. Редакс же позволяет представлять хранилище в виде композиции. Другое дело, что механизм middleware предоставляет вам возможность все это дело персистить, легко, просто и удобно. И это тоже прекрасно!

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

Я бы согласился с Вами, если бы эти надcтройки занимались расширением функционала, но по факту, это просто автоматизации рутинных процессов или внесения конструктива в синтаксис, предлагаемый из коробки.
UI в сущности своей синхронен, ведь в 100% случаев является функцией от состояния. Это состояние может быть размазано по разным слоям с прямым доступом (как, например, в классических императивных подходах), а может быть собрано воедино в одном месте декларативно (да, через ту самую композицию), что и предоставляет редакс. Почему же тогда добавление «надстроек» над этим механизмом для, например, обработки асинхронщины, длинных транзакций и т.п. не является расширением?
SOLID
Не уверен что SOLID в полной мере применим к функциональной парадигме.
> Потому что observer подразумевает императивную работу, тогда как редакс, опять таки, не про это.

Вы здесь не правы. Сравнивая с теми же сагами: саги = observable с формальной точки зрения, это просто разный интерфейс для обращения к одной и той же сущности (генераторы и observable полностью взаимозаменяемы). То есть вы пишете одно и то же (там и код-то получается предельно похожим), и с точно тем же результатом, просто несколько «на другом языке». Собственно, есть же: https://redux-observable.js.org/ с тем самым observable-интерфейсом для саг (которые называются эпиками), аналогично, в ngrx/store для обработки состояния тоже свои observable-саги, именуемые эффектами.

В чем саги выигрывают: генераторы — это поддерживаемая на уровне языка идиома, а observable — эмуляция. С-но, решение на сагах, назовем так, «чище» в плане отсутствия лишних сущностей.
У меня сложилось впечатление, что речь шла не про redux-observable, а про mobx, а это уже другая история.
Да, я о самом тезисе: «observable плохо стакается с redux». Хорошо стакается, а раз так — то причина, по которой mobx «не о том» — это не потому, что там observable (как видно, есть, как минимум, два разных варианта работы с редаксом через observable, и саги, которые по сути те же observable, просто с другого ракурса). Видимо, есть какая-то другая причина :)
То есть важно, как mobx с этим observable работает. Именно в этом зарыта императивность, а не в самом наличии observable.

Ну и выше был не только контекст mobx'a, речь шла и об observable-коллекции экшонов с диспатчем по подписке — а это практически в чистом виде effects из ngrx (да и сам стейт в ngrx тоже имеет observable-интерфейс).

И как же mobx с этим observable работает, что аж императивность тут зарыта?

Я немного неверно выразился. Видимо, следовало:

> То есть важно, как mobx с этим observable работает. Именно в этом может быть зарыта императивность, а не в самом наличии observable.

А по самому вопросу — например, она может выражаться в том, как изменяется в mobx стейт (через аналог двустороннего биндинга вместо изоляции при помощи actions)

Поясните почему action в mobx являются недостаточно изолированными...

Не actions не изолированы, а апдейт стейта. Потому что его можно апдейтить просто через x = y. Чем это отличается от старого доброго двустороннего биндинга из первого ангуляра?

Это и есть двусторонний биндинг… Все еще не понимаю, что такое "изолированный action".


Кстати, если такая возможность вас расстраивает — в mobx ее можно отключить.

есть, как минимум, два разных варианта работы с редаксом через observable

ещё mobx-state-tree умеет прикидываться redux-ом:


Пример
import React from 'react'
import { render } from 'react-dom'
import App from './containers/App'
import 'todomvc-app-css/index.css'

import { Provider } from 'react-redux'
import todosFactory from './models/todos'
import { asReduxStore, connectReduxDevtools } from 'mobx-state-tree'

const initialState = {
    todos: [{
        text: 'learn Redux',
        completed: false,
        id: 0
    }]
}
const todos = window.todos = todosFactory.create(initialState)
const store = asReduxStore(todos)
connectReduxDevtools(require("remotedev"), todos)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
Не лучший пример, где дочерний компонент управляет состоянием родительского (appActions.setLoading(true/false)).
Покажите как с помощью redux сделать так: app.IsLoading = app.postForms.some(f => f.IsLoading)

Поле вычисляемое, может лучше сделать его через селектор и не хранить в сторе? (Стор должен быть минимальным и хранить минимум инфы, всю выводимую/вычисляемою инфу нужно выносить в селекторы).


А селектор так и будет выглядеть:


const isAppLoading = createSelector(
  [postForms],
  any(prop('isLoading'))
);
По вашему примеру есть ряд замечаний. Во-первых:
const reset = createAction(`${NS}RESET`)
const set = createAction(`${NS}SET`)
const setField = createAction(`${NS}SET_FIELD`)
const setErrors = createAction(`${NS}SET_ERRORS`)
const setError = createAction(`${NS}SET_ERROR`)
const setSubmitting = createAction(`${NS}SET_SUBMITTING`)
const save = () => ({ type: `${NS}SAVE` })

Это уже чит, так как вы не используете явных констант, более того — ваши константы вычисляются, а значит, вы сходу потеряли возможность типизации пейлоада внутри редьюсера. А поскольку createAction не имеет никакой информации, кроме константы типа, то и типизация action creator тоже потеряна.

Далее, представьте, что у вас там не одно поле — а 30, а валидацию надо проводить по ходу заполнения полей (а не скопом при отправке). Кажется, предложенное решение не слишком хорошо на это дело скейлится, в любом случае.

И последнее:
const reducer = createReducer(
  {
    [reset]: () => ({ ...initialState }),
    [set]: (state, post) => ({ ...state, ...post }),
    [setField]: (state, { key, value }) => ({ ...state, [key]: value }),
    [setErrors]: (state, errors) => ({ ...state, errors: { ...errors } }),
    [setError]: (state, { key, error }) => ({
      ...state,
      errors: { ...state.errors, [key]: error },
    }),
    [setSubmitting]: (state, isSubmitting) => ({ ...state, isSubmitting }),
  },
  initialState,
)

Вы же тут сделали первый важный шаг — заменили стандартный редьюсер с кейзом по типам на набор функций (каждая функция соответствует одному экшону), а имя функции — привязывается к самому экшону. Почему бы не сделать второй шаг — зачем вообще нужен экшон и пейлоад, если можно просто передать содержимое пейлоада в аргументах функции? Т.о. пейлоад — аргументы ф-и, имя экшона — имя ф-и, сама ф-я автоматически в себе содержит action creator, а вызов следует приравнять к диспатчу action'а. В результате у вас одна обычная функция вместо целой машинерии.
Почему бы не сделать второй шаг

Мопед не мой. Покажите пример кода, как вы себе представляете API. Я может быть возьмусь за реализацию.


вы сходу потеряли возможность типизации пейлоада внутри редьюсера

не вижу преград для типизации { key, value }


[setField]: (state, { key, value }) => ({ ...state, [key]: value }),

вы не используете явных констант

А они не нужны, используются только для дисплейных имён в Redux DevTools.

Дисклеймер: я ни разу не профессиональный фронтенд-разработчик, поэтому мое мнение — безграмотное имхо.
И опыт react крайне мал, несколько простейших для-себя сайтов


Как-то я пытался изучить Redux, но в итоге мне это не понравилось. Конечно, идея однонаправленного потока данных хороша, но очень, очень много boilerplate кода. Слишком.


Да и Redux не полностью использует сам React (поправьте, если ошибаюсь, но вроде там не используется state самих компонентов?)

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

Говарят, что сложность redux — «защита от дураков». На мой взгляд — сложность redux — ломание системного мышления специалистов. Хорошо это или плохо — не знаю.

А можно подробнее, что толкнуло на этот вывод после того, как задание было сдано? Слишком сложно? Слишком долго? Говнокод?

1, 2, 3.
4 — бось в отсутсвии стандартизации, мы можем под эту гребёнку можем привести всё.
С таким же успехом можно сравнить и vuejs. (сравнивать с angular1 — это не справедливо)
Вы сравниваете «горячее» и «круглое», потому как angular это уже огромная инфраструктура, в то время как react — это только представление, а redux — это менеджер состояний.
Считаю что redux в этом смысле больше следует философии UNIX, чем концепция «давайте сделаем все в одном».

Описание экшенов и прочего — это скорей элемент бизнес-логики чем интерфейсный. Тем более это дает вполне приятно тестировать эту самую логику.

Но если вам не нравиться redux — есть например altjs (mutable state) или другие имплементации flux.
Практически соглачен со всеми Вашими посылами, но делаю другой вывод, возможно смотрю просто с дугого ракурса.
Один из главных посылов, что я тут пытался высказать:
Ценность инструмента, прямо пропорционально количеству работы, что он упрощает


И вот redux чистом виде, на мой взгляд, не удовлетворяет этому. Redux слишком низкоуровнев.
Да, сообщество уже создало множесто решений для упрощения работы, и коллеги выше привели часть из них, но не делает ли это проблему ещё более насущей?
А если интсрумент плох, имеен ли смысл его использовать только потому что он захайпился?

С таким же успехом можно сравнить и vuejs. (сравнивать с angular1 — это не справедливо)

К сожалению, с vuejs знаком только в формате демок, в реальном приложении ещё не довелось использовать, но то что я для себя вынес — vuejs на одном уровне с react, тогда когда angular1 ~= (react + redux) — (routers + ...). И я не в коем случаи на сравниваю react с angular1, извиняюсь, если ввёл Вас в заблуждение.

Советую познакомиться поближе, после реакта почему-то на vue кайф писать.
Есть конечно там своя бюрократия, но ее не очень много.
Да и приятностей встроенных в 28 гзипнутых килобайт довольно много, я удивился когда в итоге под каждый случай находил безкостыльное решение в самом фреймворке.
И мне очень понравилась документация, всем бы такую.


Ну и vue-cli мне понравился сильно больше чем create-react-app, никаких танцев с бубном чтобы подключать scss, или, например, pug.
C тайпскриптом пошаманить придется, но сегодня увидел что умельцы уже сделали все готовое https://habrahabr.ru/post/330400/ .


Если нравится jsx — то на нем тоже можно писать во vue.

Когда человек только приходит в frontend, особенно, если это его первый язык, который работает с ui, то он удивляется, как просто с помощью html тегов сделать список, добавить картинки и кнопки и при просмотре уроков уже прикидывает, что он скоро сделает. И вот он содится писать свое первое творение и застывает с глупым выражением на лице, ведь он даже не знает с какой стороны подступить раздувающемуся коду (события, подписка-отписка и прочие), а в конце ещё приходит осознание что нет ни единой мысли, как сделать слайдер или карусель.
Тогда на помощь приходит jQ, которая делает реально огромную работу за программиста, а главное делает её легкой.

Потом, уже закореннелые новички читают о фраймворках и выбирают реакт! Молодцы! Искренне. Они его открывают и точно так же как и в первые моменты своего начала, они сидят с отрешенным выражением лица не зная что делать. И тут приходит человек, говорящий и показывающи-тыкающий носом, как нужно написать приложение с помощью Redux. Все обожествляют творца вначале, а тех кто его критикует — минусуют и банят!
И вот пролетает ещё полтора года и человек пишет подобное.

Но это не из-за того что создатель Redux плохой, или из-за того что реакт кривой или ещё что-то…
Дело в том что ДАЛЬШЕ никто носом не тыкает! Ведь если разобраться, редакс, это только малая часть архитектуры, которая нужна в реальности. Просто те кто это знает не говорит об это из-за тог что их когда-то за подобное забанили или по каким-то другим причинам. а в большинстве случае и не знают, так как реакт вообще не очень полюбили те, кто реально знаком с архитектурой.

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

Помнится, когда поизучал 3 дня первый angular, я не понял, за что его хвалят то? Чувствовалось, что он явно через чур усложнен. Спустя несколько месяцев работы с ним, мое мнение о нем только ухудшилось. Со временем же стало появляться все больше статей о недостатках Angular.

К счастью был создан React. С ним гораздо медленнее старт проекта, но зато дальнейшая разработка гибче и проще чем с Angular 1.

Когда я попробовал популярный к тому времени Redux, я опечалился и мне захотелось попробовать Angular 2). Потом подумал, ну не так хорош Redux, чтобы на долгие годы стать стандартом, через 2-3 годика что-нибудь другое наберет популярность. В общем, я отказался от использования Redux в новом проекте. В голове было свое решение, основанное на библиотеке object-path, которое недолго было реализовывать, что я и сделал. Писать велосипед обычно плохое решение, но что делать, если достаточно хорошей библиотеки нет.

Потом набрал популярность Mobx. Поразбиравшись с ним немного, решил, что это приемлемое решение и в следующем проекте использовал его. Оказалось, что в реальном приложении кода приходится писать немного больше, чем в примерах. Но это мелочи. При написании я стал чувствовать себя сапером) Постоянно приходилось прокручивать в голове – все ли я учел, ничего ли не забыл, а то что-нибудь снова взорвется не заработает и придется долго искать ошибку.

Решил вернуться к своему решению, доработав его немного. И тут мне пришла в голову идея, как его прям сильно улучшить, что я и сделал.
В общем, в текущем проекте я пишу кода даже меньше, чем при использовании mobx. Причем без всякой магии и при этом реактивность осталась – компонент обновляется при изменении какого-нибудь свойства в объектах стора или стейта.

К чему я все это?
Просто хочу сказать, что если прям чувствуешь, что это недостаточно хорошее решение, так зачем его брать? При выборе надо думать своей головой, а не руководствоваться только количеством звёздочек на гитхабе, как делает большинство. Понятно, что это не всегда возможно ввиду отсутствия времени или других факторов.
Я тут свои ощуения разделяю на 3 части.
1. Апатия: Выбор каждого, как и чем пользоваться, не нравится redux, выбирай что нравится.
2. Смерение: Не будешь сейчас использовать redux, можно даже не расчитывать на достойные предложения о работе, случись то, то что нужнен реальный опыт использования.
3. Страх: Сбербанк задумался над использованием в своих решения. Сколько уже стартануло проектов? Уверены ли мы, как индустрия, что это именно то, что нужно?

Так получилось, что мы самое свободное и децентрализированное сообщество программистов. Наверно это не удивительно, учитывая всю историю web. А с другой стороны наш «frontend» ещё младенец, по сравнению с другими стеками технологий. Значит ли это, что просто нужно подождать и переболеть всеми полурешениями? Лично мне кажется, что стоит заглянуть в родственные стеки используемых в Android, iOS приложених перед которыми стоят похожие проблемы и проанализировать как они решили их.
Знакомство с первым AngularJS у меня так и не состоялось, отпугнули как раз вот такие слухи о его сложности и неудобности. Но вот со второй версией случилась любовь с первого взгляда. Восхитило, насколько в нем все логично и просто устроено. Не считая, конечно, некоторой сложности в сетапе и сборке prod-версии (это был rc1, никакого Angular CLI еще не было в помине). Но, спасибо webpack-у за наше счастливое детство, сложности эти были легко преодолены.

К чему эти дифирамбы? Просто на главной странице документации redux написано, что его можно использовать с чем угодно, не только с react-ом, но и с Angular 2+. Но за все время разработки на последнем, я так и не смог придумать, для чего мне мог бы пригодиться redux.
А как вы работаете с глобальным стейтом? Когда нужно обмениваться информацией между компонентами, причем эти компоненты в дереве расположены сильно далеко друг от друга (по-этому прокидывать инпуты/аутпуты — сильно не вариант)? Общий сервис с observable?
Не использую общий глобальный стейт и придерживаюсь обычно следующих принципов:

  1. деление компонентов по типу Presentational и Container Components (https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0)
  2. каждый «корневой» компонент (как правило, привязанный к опредленному роуту) получает свое актуальное состояние с бэка при инициализации или изменении параметров роута
  3. корневые компоненты между собой не общаются, только через бэк
  4. корневой компонент как правило является Container Component-ом и для отрисовки передает/получает свойства своего состояния через цепочки input/output дочерним Presentational Component-ам (или, если куски большие, разбивать на несколько дочерних Container Component-ов

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

Эти принципы подробно описаны в официальной документации Angular-а и, как мне показалось, являются тем самым angular way.

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

Если стейт хранится на беке, то как его потом синхронно обновить? Вот у вас есть несколько несвязанных компонент, каждая из которых подтягивает копию некоторого стейта с бекенда, в одной из компонент стейт обновили => он ушел на бекенд, как обновить остальные копии стейта, в других компонентах? Какая часть программы отвечает за то, что остальные компоненты сделают в этот момент запрос к бекенду и обновят свой стейт? Или в таких случаях только руками через output и надеяться, что не придется прокидывать слишком далеко?

> Эти принципы подробно описаны в официальной документации Angular-а и, как мне показалось, являются тем самым angular way.

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

Исходя из моих принципов, у меня в любой момент времени нет нескольких несвязанных компонентов, общающихся с бэком. Всегда есть только один корневой (грубо говоря, текущая страница) привязанный к текущему роуту. Если роут меняется (не путать с изменением параметра роута), то этот компонент уничтожается, и создается новый компонент согласно новому роуту. И уже он грузит свой актуальный стейт с бэка.
Ну вот у вас общая шапка для всех роутов с именем текущего пользователя. И страница с профилем пользователя. Вот он редактирует свое имя — как вы обновите шапку? Output'ы до корня?
При создании SPA, те самые элементы, которые на серверных языках я бы реализовывал через хранение данных в сессии (тот же профиль пользователя), приходится использовать storage-ы и модели, которые получают данные из них.

Т.е., поставленную вами задачу я бы решал следующим образом: создал отдельный компонент Layout, который будет показываться по-умолчанию на страницах и содержит компонент c шапкой, в котором отображаются данные авторизованного пользователя, которые берутся из сессии (т. е. из storage-а). Обновлять данные в шапке можно по ngDoCheck, а чтобы это никак не сказалось на производительности, в механизм нашей сессионной модели несложно добавить проверку на последнее изменение по Timestamp-у.

Конкретно всё это безобразие можно реализовать и другими способами (от предложенного общего сервиса, до синглтона-хранилища-состояний). Но у использования того же localStorage в данном конкретном примере очевидны свои плюсы.

Но это, опять же, если я правильно понял ваш пример. Часто годятся и «оутпуты до корня». Пример: личный кабинет пользователя — корневой компонент. При создании загружает актуальные данные о пользователе и хранит их в себе. Имеет два дочерних компонента: Presentational — лэйаут (использую в нем transclusion посредством ng-content) отрисовывающий шапку, футер, и место, куда будет помещен второй дочерний компонент с формой редактирования данных пользователя. По сути, в данной схеме будет использован всего один output — от компонента с формой редактирования до корневого личного кабинета. Который после получения новых данных о пользователе тут же отобразит их в лэйауте (в шапке, без всяких ngDoCheck). И в такой схеме я вообще не вижу необходимость какого-то глобального стейта.
которые берутся из сессии (т. е. из storage-а)
И чем это отличается от redux-стора?
Очевидно, своей простотой и поддержкой браузерами по-умолчанию. Плюс, грамотное использование localStorage решает вопрос, когда пользователь в вашем SPA-приложении пытается открыть ссылку в новой вкладке.
Ну я вам ваши же слова адресую:
Не использую общий глобальный стейт
А то, что вы вместо одного стораджа предпочитаете другой, абсолютно ничего не меняет.
Я там в конце сделал сноску, что в редких случаях все же допускаю их использование. Но только в тех случаях, когда реально без этого не обойтись, как правило для сессионных данных. Ну хотя бы тот же токен пользователя надо как-то хранить, а не заставлять его авторизовываться заново, если ему приспичит нажать F5.
Так вся эта ветка как раз о том, что без глобального состояния все-равно не получится. Так почему бы не отдать работу с ним инструменту, специально под это заточенному, удобному и простому как 3 копейки, вместо своих велосипедов?
> Конкретно всё это безобразие можно реализовать и другими способами (от предложенного общего сервиса, до синглтона-хранилища-состояний). Но у использования того же localStorage в данном конкретном примере очевидны свои плюсы.

https://github.com/btroncone/ngrx-store-localstorage

У меня аналогично с первым Angular, с redux. Но mobx прижился. Не так много наступил на грабли, как пугали. Главное не забывать про рекомендации.

в конце то концов, не может же ошибаться целая индустрия?
Еще как может :)
У меня была похожая реакция. Может я просто слишком тупой для redux'а, но вся эта куча констант и экшны меня совсем не привлекают. Вздохнул с облегчением, когда обнаружил для себя MobX

А теперь можно посмотреть на https://vuex.vuejs.org и плакать горькими слезами от того, как криво это сделано в redux.
Но redux, как начало очень сильно помог. Но чем дальше, тем больше об будет мешать, вот моё мнение.

Интересно, что на моей памяти люди именно с vuex на redux и сбегают. Недавно один знакомый заменил vuex на redux + revue, сказал, что всё стало заметно проще и лучше.

здесь может иметь значение какая версия vue+vuex используется. если первая, то согласен, если вторая то нет.
На меня просветление снизошло после https://habrahabr.ru/post/235121/
VueJS идет в ту же сторону, но можно сделать лучше.
Не хватает варианта «Не использую».
Часто в подобных опросах такой вариант становится лидирующим и портит вид общей статистики. Именно для этого на хабре есть кнопка воздержаться.

В данный момент: Проголосовало 152 человека. Воздержалось 150 человек. Полагаю, эти 50% пользователи как раз таки «не используют» redux.
UFO just landed and posted this here

Вам еще не надоело хаить инструменты? Тут ведь все сводиться к делу вкуса: кто-то любит низкоуровневый Redux, где ты контролируешь весь поток данных, кто-то любит абстракции и магию, не задумываюсь о реализации всего этого. Но с чего это ваши личные предпочтения вдруг делают %инструмент_нейм% ужасным, неэффективным и вообще использование его становится моветон. Есть же альтернативы, так используйте их, зачем писать эти статьи? Я как новичок из них ничего не получу, так как легко могу найти статьи за и против любого инструмента. Все равно придется пробовать самому.
Кому-то нравится электродрель, кому-то молоток и гвозди, а кому-то легче нанять рабочих и вообще не париться.

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

В первое время при работе с redux льстило, что кругом ФП, чистые функции, иммутабельность. Но потом все
это прошло, и я теперь скромно использую MobX.
Серебряной пули как известно не существует. Выбирайте технологию которая подходит для Вашего проекта — решает его задачи максимально эффективно.
Я для себя вывел условную градацию для state менеджмент систем:
  • «Большой, могучий enterprise проект», большая команада — Redux
  • Небольшая команда, 1-3 человека — можно использовать MobX
  • Очень кастомный проект, например графический редактор — RxJS + React State

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

Выбирайте технологию, а не то технология выберет Вас.
А я поддерживаю автора.У меня был похожий опыт.Я тоже столкнулся с тем что описывает автор
Redux действительно непросто использовать в средних и крупных проектах, особенно когда бизнес-аналитика часто меняет свои решения по поводу функционала дизайна и пр. Поэтому, все эти примеры из туду листов и генераторы бойлерплейтов не особо работают в таких проектах. Так же сложности добавляет тот факт, если работает над проектом не один человек, а 4-5-n. Тогда эти бесконечные гигабайты шаблонного кода с action_types, actions и reducers точно начнут сводить с ума, если с ними ничего не придумать.
Один из вариантов решения проблемы, который к слову работает в продакшне, среднего+ проекта, частично решает вышеописанные проблемы https://github.com/welljs/react-redux-mvc. Может показаться, что с паттерном mvc погорячился, но идея именно в том, чтобы довести фреймворк до состояния близкого к mvc

Принцип прост: компонента react (view) — тупо рисует то, что получила через props от Model. Model — обертка вокруг redux, это то место где формируется грубо говоря json-представление прикрепленной к ней вьюхи, Controller — связывает model и вью, а так же обрабатывает ui-события.

Структура проекта получает следующий вид
/classes - классы для работы с данными

/components - компоненты. тупые умные, не важно. компонуются по принципу - все что нужно компоненте, лежит в ее директории

/layouts - лэйауты - с сайдбаром, без сайдбара, логин, лэндинг ...

/pages - страницы, и компоненты принадлежащие конкретной странице. Также компонуются по принципу, все что нужно лежит в одной директории. Если компонента становится общей для нескольких страниц, обычно достаточно Ctrl+X -> Ctrl+V в папку с компонентами. Умная IDE пути в импортах сама исправит

/redux - экшны для получения данных не имеющих привязки к конкретной вьюхе, например user, agreements, partners

/utils - всякое


Из плюсов: сравнительно легко объяснить принцип работы, дебажить, тестировать, компоновать-перекомпоновывать, шарить компоненты и т.п.
Из минусов: все еще приходится писать немного шаблонного кода, есть небольшие недоделки и не полностью реализован весь замысел

Если кому станет интересно, буду рад почитать отзывы, а если вдруг даже появятся контрибуторы, тогда точно буду знать, что проект годный
Шутка про 100 лучших js фреймворков.
сбербанк сделал redux основой своего стека

Если речь о sberbank.ru — они используют платформу Backbase, и там уж «основу» получают как есть. Или речь о мобильных приложениях?
React и его экосистема — относительно низкоуровневые инструменты. Когда появятся серьезные высокоуровневые фреймворки на их основе — вот тогда точно заживём.
Для получения кучи данных использую GraphQL и Apollo (который под капотом использует redux, ну да ладно). Забыл о куче экшенов и прочего как страшный сон. Для зависимых данных есть MobX. А для состояния интерфейса в большинстве случаев хватает стейта контейнера и глупых компонентов в нем.
Для зависимых данных есть MobX

Поясните, пожалуйста

Sign up to leave a comment.

Articles