Redux - несколько магазинов, почему бы и нет?

221

Как примечание: я прочитал документы для Redux (тоже Baobab), и я сделал немалую долю в Google и тестировании.

Почему так настоятельно рекомендуется, чтобы приложение Redux имело только один магазин?

Я понимаю плюсы и минусы настройки одного магазина по сравнению с настройкой нескольких магазинов ( Есть много вопросов и ответов по SO на эту тему ).

ИМО, это архитектурное решение принадлежит разработчикам приложений на основе потребностей их проектов. Так почему же это так настоятельно рекомендуется для Redux, почти на грани звучания обязательно ( хотя ничто не мешает нам создавать несколько магазинов )?

РЕДАКТИРОВАТЬ: обратная связь после преобразования в один магазин

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

Несколько моментов, которые могут помочь другим понять, почему один магазин против многих является спорным вопросом во многих, многих случаях использования:

  • это надежно : мы используем селекторы, чтобы рыться в состоянии приложения и получать контекстную информацию. Мы знаем, что все необходимые данные находятся в одном магазине. Это позволяет избежать любых вопросов относительно того, где могут быть проблемы государства.
  • это быстро : в нашем магазине сейчас около 100 редукторов, если не больше. Даже при таком количестве данных лишь немногие редукторы обрабатывают данные в любой конкретной отправке, остальные просто возвращают предыдущее состояние. Аргумент, что огромный / сложный магазин ( nbr редукторов ) медленный, в значительной степени спорный. По крайней мере, мы не увидели никаких проблем с производительностью.
  • дружественная отладка : хотя это наиболее убедительный аргумент в пользу использования избыточности в целом, он также подходит для одного хранилища против нескольких хранилищ. При создании приложения вы должны иметь ошибки состояния в процессе ( ошибки программиста ), это нормально. PITA - это когда отладка этих ошибок занимает несколько часов. Благодаря единственному хранилищу ( и избыточному логгеру ) мы никогда не тратили больше нескольких минут на какую-либо проблему состояния.

несколько указателей

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

{
  apis: {     // data from various services
    api1: {},
    api2: {},
    ...
  }, 
  components: {} // UI state data for each widget, component, you name it 
  session: {} // session-specific information
}

Надеюсь, этот отзыв поможет другим.

РЕДАКТИРОВАТЬ 2 - полезные инструменты магазина

Для тех из вас, кому интересно, как «легко» управлять одним магазином , который может быстро стать сложным. Есть инструменты, которые помогают изолировать структурные зависимости / логику вашего магазина.

Существует Normalizr, который нормализует ваши данные на основе схемы. Затем он предоставляет интерфейс для работы с вашими данными и извлечения других частей ваших данных id, подобно словарю.

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

Себастьян Даниэль
источник
4
Мне нравится ваш подход к структуре магазина, который вы используете; Тем не менее, как вы обрабатываете изменения состояния API, соответствующие изменениям состояния вашего компонента? Скажем, я получаю специфичные для домена данные из моего API, как это может привести к общей структуре данных, которая будет обнаружена в моих компонентах?
Diniden
Как ваши компоненты отображают / используют данные магазина, зависит от вас. Хотя я думаю, что не до конца понимаю ваш вопрос, не могли бы вы уточнить или начать сеанс чата?
Себастьян Даниэль
2
Я предполагаю, что вопрос был бы так: ваши компоненты визуализируют какой-либо из состояния API или они отображают только то, что помещено в состояние компонентов. Я подозреваю, что если вам удалось выполнить ТОЛЬКО рендеринг из состояния компонента, то вы нашли отличный способ сделать ваши компоненты и контейнеры пригодными для повторного использования даже при наличии данных, специфичных для домена. Если ваши компоненты визуализируются частично из состояния API и состояния компонента, то я предполагаю, что вы используете специфичные для домена контейнеры для сопоставления данных в apis с общими списками и примитивами, которые понимают ваши компоненты.
Diniden
2
Я использую Redux в сочетании с селекторами, которые в основном запоминаются функционально-чистыми преобразователями данных. Каждый компонент «реагирует» на сохранение обновлений, и если изменение относится к нему, он «выбирает» данные и отображает их соответствующим образом. Так что да, компоненты отображаются только на основе того, что для них важно. Но это не только из-за Redux или структуры магазина. Это связано с сочетанием неизменяемого хранилища данных, теста сравнительного сравнения изменений данных и чистого селектора, который выбирает данные, необходимые компоненту, в нужном формате.
Себастьян Даниэль
Привет @SebastienDaniel, не могли бы вы показать пример того, как вы реализуете проверку, которую каждый компонент делает, чтобы узнать, имеет ли отношение изменение в обновлении магазина к нему? Я имею в виду, если вы используете какой-то общий шаблон ... или если в каждом конкретном случае вы проверяете, изменились ли данные, относящиеся к конкретному компоненту.
Джон Бернардссон

Ответы:

232

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

Почему мы подчеркиваем это в документах? Поскольку большинство людей, пришедших из Flux, полагают, что несколько магазинов - это решение сделать модульный код обновления. Однако у Redux для этого есть другое решение: состав редуктора.

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

  • Использование композиции редуктора упрощает реализацию «зависимых обновлений» в стиле waitForFlux путем написания редуктора, который вручную вызывает другие редукторы с дополнительной информацией и в определенном порядке.

  • С одним магазином очень легко сохраняться, увлажнять и читать состояние. Рендеринг сервера и предварительная выборка данных тривиальны, потому что существует только одно хранилище данных, которое необходимо заполнить и повторно скопировать на клиенте, и JSON может описать его содержимое, не заботясь об идентификаторе или имени магазина.

  • Единый магазин делает возможными функции путешествия во времени Redux DevTools. Это также упрощает такие расширения сообщества, как redux-undo или redux-optimist, поскольку они работают на уровне редуктора. Такие «усилители-редукторы» не могут быть написаны для магазинов.

  • Одно хранилище гарантирует, что подписки вызываются только после обработки отправки. То есть к моменту уведомления слушателей состояние уже полностью обновлено. Во многих магазинах таких гарантий нет. Это одна из причин, по которой Flux нужен waitForкостыль. С одним магазином, это не проблема, которую вы видите в первую очередь.

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

Дан Абрамов
источник
11
Я признаю, что не понимал всех преимуществ / необходимости композиции редуктора. Благодаря вашему ответу я еще кое-что прочитал и показал пример (опять же TodoMVC). С таким небольшим примером было трудно понять фактическое улучшение, обеспечиваемое составом восстановителя. Однако, немного подумав, в широком масштабе выигрыш (сейчас) очевиден. Еще раз спасибо, отличный ответ!
Себастьян Даниэль
4
@Sebastien Я думаю, что пример "корзины покупок" лучше для этого.
Дан Абрамов
3
Я медленно внедряю избыточность в традиционное (не SPA) приложение. Я использую многопользовательские хранилища для каждого «целого», которое я конвертирую в реализацию реагирования / избыточности, пока все приложение не может быть изменено для использования одного и того же хранилища.
Пол Кнопф
5
@DanAbramov Интересно, что вы думаете о ситуации, в которой ваше основное «приложение» запускает собственный магазин Redux и импортирует через npm отдельное «приложение», которое запускает собственный отдельный магазин Redux. Например, если одна из других команд в вашей компании имеет какую-то службу обмена сообщениями с пользовательским интерфейсом, который вы хотите использовать, не загрязняя свой магазин этими данными.
natlee75
6
@ natlee75 "Некоторые веские причины для использования нескольких хранилищ в Redux могут включать: [...] Изоляция приложения Redux как компонента в более крупном приложении, и в этом случае вы можете создать хранилище для каждого экземпляра корневого компонента." Из redux.js.org/docs/FAQ.html#store-setup-multiple-stores
Кевин,
24

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

Например, я склонен рассматривать следующие общие функциональные области как отдельные приложения:

  • Администратор
  • Аналитика / данные с панелей мониторинга
  • Управление биллингом и потоки покупок
  • Корпоративная учетная запись / управление разрешениями

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

Лучший способ управлять очень большими приложениями - это рассматривать их как композицию множества небольших приложений.

Если ваше приложение меньше, чем, скажем, ~ 50k LOC, вы, вероятно, должны игнорировать этот совет и следовать совету Дэна.

Если размер вашего приложения превышает 1 миллион LOC, вам, вероятно, следует разделять мини-приложения, даже если вы поддерживаете их в режиме моно репо.

Эрик Эллиотт
источник
5

Это архитектурное решение принадлежит разработчикам приложений на основе потребностей их проектов.

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

  • Это ненадежно, потому что части магазина не изолированы.
  • Это неэффективно, потому что вы клонируете и пересекаете хэш-три. Когда мутации растут арифметически - сложность растет геометрически. Вы не можете исправить это путем рефакторинга каких-либо редукторов, селекторов и т. Д. Вы должны разделить свою базу данных.
  • Когда это становится медленным, никто не хочет разделить это на отдельные приложения с отдельными магазинами. Никто не хочет тратить деньги на рефакторинг. Люди обычно конвертируют некоторые умные компоненты в дамп и все. Знаете ли вы, какое будущее ждет разработчиков излишков? Они будут поддерживать эти ады.
  • Это не дружественная отладка . Трудно отлаживать соединения между практически изолированными частями магазина. Очень сложно даже проанализировать количество этих связей.

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

Один неизменный магазин с однонаправленным потоком - не эликсир для каждой болезни. Если вы не хотите поддерживать архитектуру проекта, вы все равно будете страдать.

puchu
источник
Мне понравилось то, что вы сказали, и здесь я задал соответствующий вопрос по этому вопросу. Не могли бы вы взглянуть на это, когда уделите время и поделитесь своим мнением? Вопрос, который я задал в Reddit, потому что SO не поощряет такие вопросы здесь.
Arup Rakshit
3

Несколько хранилищ могут быть полезны в следующих случаях использования 1. Если у вас есть большие компоненты, которые не зависят друг от друга с точки зрения структуры данных, поведения, контекста приложения. Изоляция этих компонентов облегчает управление вашими данными и потоком приложений. Это также помогает независимой разработке и обслуживанию ваших компонентов. 2. Проблемы с производительностью: не типичный вариант использования, но если некоторые из ваших компонентов обновляются очень часто и не влияют на другие компоненты, возможно, вы можете пойти в другие магазины.

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

newtonflash
источник
Ваше сообщение выглядит как «всегда использовать избыточность, за исключением нескольких случаев» == «вам не нужна архитектура проекта, за исключением нескольких случаев». Это очень близко к реальности, я счастлив.
Пучу
2

почему мы не можем использовать несколько магазинов с использованием RedEx ????

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


Могу ли я создать несколько магазинов? Могу ли я импортировать свой магазин напрямую и самостоятельно использовать его в компонентах?

Исходный шаблон Flux описывает наличие нескольких «хранилищ» в приложении, каждое из которых содержит отдельную область данных домена. Это может привести к таким проблемам, как необходимость обновления одного магазина «waitFor» в другом магазине.

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

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

Некоторые допустимые причины использования нескольких магазинов в Redux могут включать:

Решение проблемы с производительностью, вызванной слишком частыми обновлениями некоторой части состояния, что подтверждается профилированием приложения. Изоляция приложения Redux как компонента в более крупном приложении, в этом случае вы можете создать хранилище для каждого экземпляра корневого компонента. Тем не менее, создание новых магазинов не должно быть вашим первым инстинктом, особенно если вы пришли из Flux. Сначала попробуйте составить редуктор и использовать несколько магазинов, только если это не решит вашу проблему.

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

официальный документ по редуксу

Ризо
источник
1

Наличие одного магазина в Redux - это действительно то, что нам нужно во многих случаях, я использовал Redux и Flux и считаю, что Redux делает свою работу лучше!

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

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

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

Алиреза
источник
3
Таким образом, все должны верить, что один магазин сделает работу лучше, и никто не мог объяснить почему. Это мне что-то напоминает ...
Пучу