Как стать автором
Обновить

Комментарии 40

Redux — это детище создателей ядра React.

Ден Абрамов написал Redux ещё до присоединения к команде Реакта, если не ошибаюсь (по крайней мере, он не был сотрудником FB)
Лично я обожаю MobX. Но, к сожалению, «отраслевым стандартом» считается Redux.
MobX потихоньку тоже становится стандартом.
подтверждаю, последние два года попадается только Mobx слава богу)
Хотелось бы, чтобы MobX был стандартном.
Но я не встречал ни одного готового шаблона админки или фреймворка с Mobx(
Если какие-то готовые компоненты используют менеджер состояний, то это почти всегда redux(
Еще recoil появился. Из-за того, что он от разрабов фейсбука, у него большой шанс стать стандартом в будущем.
Плюс в современных примерах а-ля «есть context и хуки, наконец-то можем проще, без redux» по-прежнему по привычке тянут эти редьюсеры, диспетчеры. Эх, испортил Ден фронтенд основательно и надолго(
Самый большой фейл в экосистеме React'a — это связка с Redux и ему подобным хламом.

Самый большой фейл многих разработчиков которые пишут на React'e — не знание того, что есть MobX и то, что Redux давно должен лежать на помойке.

Связка React + MobX делает из React'a отдельную и главное реактивную технологию, уже совершенно взрослую и реально мощную. Без боли, без страданий и без тонн лютого и не поддерживаемого говнокода (который считается нормой в react+redux апликухах).

Мне кажется, что автор Redux пытался изобразить https://www.martinfowler.com/eaaDev/EventSourcing.html на джаваскрипте. Получилось10 строчек кода и тут он обрёл просветление. Я не вижу в этом ни чего плохого, кроме попытки оставить комьюнити один на один с низкоуровневым API на несколько лет. А потом они родили redux-toolkit, и этим стало можно пользоваться без слёз.

redux-toolkit, и этим стало можно пользоваться без слёз.

Все еще со слезами на глазах, но явно лучше, чем ничего =)
У них добавлены многие штуки из коробки, но все еще не очень понятно, что делать с nested данными, особенно, если у вложенных данных нет уникальных id. А вложенность трехуровневая. (Реальный кейс, где redux-toolkit не справляется без шаманства).


С Mobx/Mobx-state-tree шаманить практически не нужно.

Интересно, а можно пример?

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

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

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


UPD: глобальным объектом в этом случае обычно делается корневой компонент приложения который виден из всех компонентов как this.ownerComponent (или this.rootComponent).

В чем преимущество компонента как глобального объекта по сравнению с контекстом?

Для передачи вниз контекст прекрасно подойдёт, а вот для передачи вверх без создания жёсткой связи он мне кажется малопригоден.


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

в контекст можно положить функцию обновления состояния, например dispatch из useReducer

Я там уже добавил обновление в свой коммент выше)).

А чем вам не подошел контекст? Отлично подходит для использования состояния компонента на любой вложенности в любом из потомков.

ИМХО меняете шило на мыло как по мне. Как минимум, вы могли бы иметь index.js файл для компонентов, в котором бы экспортился законнекченный к стору компонент, и соответственно когда вам нужна связь с хранилищем вы юзаете его, когда нет — используете напрямую Component.js. Своим подходом вы создаёте жёсткую связь (что является антипаттерном в программировании в принципе, вспоминаем high cohesion и low coupling) между компонентами.
Ну и плюс в вашем подходе нужно разбираться, у него могут быть свои подводные камни, а с redux уже всё всем понятно и всё известно. Так что как по мне, не стоит изобретать велосипед в очередной раз.

Redux позволяет писать действительно большие проекты, MobX — быстрее стартануть. Чем он лучше — сказать не могу, мне нравится насколько понятно происходящее с приложением, когда я смотрю список actions и изменения state в Reactotron (работаю React-Native). Как это было бы в MobX — хз.

Чистый redux смысла нет использовать, можно подключить redux-toolkit (или reduxsauce) чтобы не писать много лишнего кода.
Для модификаций состояний можно использовать seamless-immutable. Это если не нравиться много писать.

В приведенном примере плохо — слишком большая связность между компонентами, и state все равно в компонентах. Я не представляю как бы я поддерживал и рефакторил такую архитектуру где были бы сотни компонентов.
Для модификаций состояний можно использовать seamless-immutable

Кстати, redux-toolkit идет в комплекте с immer.js от авторов mobx (совпадение? не думаю)
Это позволяет писать простой и понятный код в редьюсерах:


const reducers = {
  resetStatusImmer = state => {
    state.meta.status = 'initial'
  },

  resetStatusCommon = state => {
    return {
      ...state,
      meta: {
          ...state.meta,
          status: 'initial'
      }
    }
  },
}
Redux позволяет писать действительно большие проекты, MobX — быстрее стартануть.

Мда, куда катится мир. Они оба позволяют писать гигантские проекты. Что за «логика» такая?
Если ты не понимаешь что происходит в твоем коде, не умеешь пользоваться console.log, не умеешь пользоваться IDE (find references / find usages и т.п.), то у меня для тебя плохие новости и никакой тут mobx или redux не поможет.

Во-первых, Ваш подход вынуждает использовать компоненты-классы вместо компонентов-функций. Это может замедлить приложение, когда оно разрастётся, не говоря о том, что их сложнее дебажить.
Во-вторых, асинхронность. Если TicketDetails получает данные через HTTP, и если таких компонентов много (а их будет много), каждому придется добавлять какой-нибудь EventEmitter или Promise для синхронизации — а это дополнительный boilerplate-код и нарушение принципа single responsibility.
Ну и в-третьих, добавление жёстких зависимостей усложняет написание юнит-тестов, добавляя больше boilerplate-кода ещё и в них.

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

О, вы хотите об этом поговорить? Вот есть классы, которые, как мы все понимаем, после транспиляции превратятся в лежащую где-то коллекцию функций (статика) и коллекцию функций в «особой» группе prototype (не статика). А теперь, давайте с этого момента поподробнее — как именно это может замедлить приложение, когда оно разрастётся?
Коллекция функций потребует больше ресурсов, чем одна функция.

Чем одна функция, у которой внутри — та же самая коллекция, только в виде анонимных замыканий? Ну-ну.

Спойлер:
Вы никогда не увидите разницу глазами в производительности между классовыми компонентами реакта и функциональными в реальных приложения.
Выигрыш одной из сторон на пару процентов вообще никакой погоды никому не делает.
А вот удобство разработки делает огромную погоду.
Переходите на vue, там можно сделать такую штуку, как реактивные контейнеры состояния (естественно, не только со свойствами, но и с методами), которые можно использовать напрямую или наследовать от них свои вычисляемые свойства. А в Vue 3 этот подход еще более расширен благодаря прямому доступу к системе реактивности.
В MobX подобное тоже есть.
Интересно, а кто будет подчищать «старье» в этом components.js? Там буду висеть ссылки на компоненты, которые уже давно не нужны. Как-то этот момент не освещен.
Вы кажется в той же ловушке, что и большинство react-разработчиков. В ловушке под названием react.
Я не к тому, что реактом пользоваться не надо, нет, прекрасная штука — нежно люблю и сам использую каждый день. Нет, я к тому, что вы разрабатываете на реакте, завязываясь на сам реакт. Ну и порождаете жесткую связанность(coupling), когда она вовсе не нужна.

Почему-то DDD пока мало проникает во фронтэнд, и мало кто отделяет доменные вещи от средства отображения. Все данные, всю логику, вообще почти все можно безболезненно отделить от реакта и это будет настоящим работающим ядром приложения без всяких отображений. Можно даже наверно сказать — это будет «реализацией стейт-менеджера», который по сути «переменная + сеттер + observable». Каждый может это сделать, а если проникнуться DDD — можно сделать это очень хорошо.
Ну не знаю, я например пишу на реакте с 2015 года, но с 2016 года использую реакт(по прямому назначению) только как view слой и не более, состояние и бизнес логика описана в MobX'e и в обычных функциях и классах хелперах.
Так что не все находятся в ловушке, но многие, к великому сожалению.
Почему-то DDD пока мало проникает во фронтэнд, и мало кто отделяет доменные вещи от средства отображения.

Это не «почему-то», а как раз потому, что модные-молодежные фреймворки прошлого десятилетия (текущие топ-3 как раз оттуда) неявно способствовали отказу от MVC (и отказу от моделирования данных по DDD, соответственно) и пропагандировали идеи в духе «ты просто фигачь свой фронт целиком на нашем инструменте, а мы как-нибудь подумаем, чтоб тебе было норм». Разумеется, вторая часть в реальности для реакта никогда не воплощалась: реакт так и остался в первую очередь инструментом контроля за доступом к DOM (для чего он собственно и разрабатывался — чтоб парням в фейсбуке стало понятно, какой код и когда у них меняет DOM). Да и у других тоже не всё шоколадно — тот же ангуляр тащит свой корявенький DI (корявенький — потому что делался очень давно и не меняется из-за соображений обратной совместимости, хотя и сейчас можно сделать значительно более цивилизованно) ради архитектуры высокого уровня, но в вопросах моделирования данных просто говорит «вот у нас тут RxJS есть, уже впиленный в ангуляр — так что вы просто пользуйтесь им».

Текущее поколение «топовых» фронтовых фреймворков пытается подменять собой все части MVC, несмотря на то, что по сей день они в основном лишь отрабатывают букву V, а в части поддержки M и C у них у всех всё крайне небезоблачно.
Отличное дополнение, спасибо!
У Vue и Svelte в плане M и C все гораздо лучше конечно из коробки. Только вот они с Tyescript'ом не сильно дружат из коробки в отличии от реакта.
Svelte, грят, уже дружит — надо как-нибудь пощупать самому, как будет время.
Так и vuejs дружит, но не без нюансов.
В том то и дело что и там и там есть нюансы, но в целом по состоянию на сегодняшний день терпимо, но все же хотелось бы лучше
В тот день, когда нам перестанет хотеться лучше — пора отправляться на кладбище.
Подход, описанный в статье, делает состояние компонента неявным, в этом соль всей этой истории с передачей пропсов снизу вверх.

Что если components.ContentArea случайно изменится каким-нибудь другим компонентом?
Что если компонент более верхнего уровня будет размонтирован, а компоненты более низкого уровня — нет?
Кроме того, сложнее становится тестировать компоненты независимо, ведь кроме передачи пропсов нужно сформировать подходящий объект components с необходимыми заглушками, ценность этих тестов также падает.
Наконец, хранение ссылок на компоненты в глобальном объекте components, особенно массива ссылок (хоть автор и не рекомендует так делать), приведет к утечкам памяти, поэтому если уж и пользоваться таким подходом, то очень аккуратно, не забываю про очистку ссылок при размонтировании компонентов.

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

Я думаю, что многие разработчики «морщатся» потому, что на интуитивном уровне понимают, что ваш подход противоречит принципам функционального программирования, в духе которого реакт и написан. И тут уже дискуссия перетекает на высокие материи =))
Зарегистрируйтесь на Хабре, чтобы оставить комментарий