Redux - кілька магазинів, чому б і ні?


221

Як зауваження: я прочитав документи для Redux (також Baobab), і я зробив неабияку частку в Google і тестуванні.

Чому так наполегливо пропонується, що програма Redux має лише один магазин?

Я розумію плюси та мінуси налаштування одного магазину проти декількох налаштувань магазину ( на цю тему існує багато запитань і відповідей ).

IMO, це архітектурне рішення належить розробникам додатків виходячи з потреб їх проектів. То чому ж так наполегливо пропонується Redux, майже до того, що звучить обов'язково ( хоча нас нічого не заважає зробити кілька магазинів )?

EDIT: відгуки після переходу на одноразовий магазин

Після кількох місяців роботи з наддувом над тим, що багато хто вважатиме складним СПА, я можу сказати, що структура єдиного магазину була чистим захопленням працювати.

Кілька моментів, які можуть допомогти іншим зрозуміти, чому один магазин проти багатьох магазинів є суперечливим питанням у багатьох, багатьох випадках використання:

  • це надійно : ми використовуємо селектори, щоб перекопати стан програми та отримати інформацію, що стосується контексту. Ми знаємо, що всі необхідні дані знаходяться в одному магазині. Це дозволяє уникнути будь-яких сумнівів щодо того, де можуть бути державні питання.
  • це швидко : наш магазин наразі має близько 100 редукторів, якщо не більше. Навіть при такому підрахунку лише декілька редукторів обробляють дані про будь-яку відправлення, інші просто повертають попередній стан. Аргумент про те, що величезний / складний магазин ( кількість редукторів ) є повільним, є суперечливим. Принаймні, ми не бачили жодних проблем із продуктивністю, які надходять звідти.
  • дружнє налагодження : хоча це найбільш переконливий аргумент для використання скорочення в цілому, це також стосується одного магазину проти кількох магазинів. Створюючи додаток, у вас обов'язково виникають помилки стану в процесі ( помилки програміста ), це нормально. PITA - це коли на помилки потрібні години для налагодження. Завдяки єдиному магазину ( та увімкненому реєстратору ) ми ніколи не витрачали більше ніж кілька хвилин на будь-яку проблему стану.

кілька покажчиків

Справжня проблема у створенні магазину редукцій - це вирішення питання про його структурування . По-перше, тому що зміна структури в дорозі - це лише головний біль. По-друге, тому що він значною мірою визначає, як ви будете використовувати та запитувати дані додатків для будь-якого процесу. Є багато пропозицій щодо структури магазину. У нашому випадку ми виявили ідеальне:

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

Сподіваємось, цей відгук допоможе іншим.

EDIT 2 - корисні інструменти магазину

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

Існує Normalizr, який нормалізує ваші дані на основі схеми. Потім він надає інтерфейс для роботи з вашими даними та отримання інших частин ваших даних id, подібно до словника.

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


4
Мені подобається ваш підхід до структури магазину, яку ви використовуєте; однак як ви обробляєте відображення змін стану api до змін вашого компонента? Отже, скажіть, я отримую дані щодо домену від мого API, як це переводиться на загальну структуру даних, яку можна знайти в моїх компонентах?
Дініден

Як ви, власне, визначаєте, як ваші компоненти компонентів відображають / використовують дані магазину. Хоча я думаю, що я не повністю розумію ваше запитання, ви могли б розробити або розпочати сеанс чату?
Себастьян Даніель

2
Я думаю, що запитання було б: чи ретранслюють ваші компоненти будь-які з стану apis, чи вони надають лише те, що переведено у стан компонентів. Я б підозрював, якби вам вдалося ТОЛЬКО візуалізувати стан штатного компонента, тоді ви знайшли прекрасний спосіб зробити ваші компоненти та контейнери дуже корисними для використання навіть за наявності даних, що стосуються домену. Якщо ваші компоненти частково відображаються із стану API та компонента, то я здогадуюсь, що ви використовуєте конкретні доменні контейнери для відображення даних у apis до загальних списків та примітивів, які ваші компоненти розуміють.
Дініден

2
Я використовую Redux спільно з селекторами, які в основному запам'ятовують функціонально чисті картографи даних. Кожен компонент "реагує" на зберігання оновлень, і якщо зміна стосується його, він "вибирає" дані та відображає відповідно. Так, так, компоненти відображаються ТОЛЬКО на основі того, що для них важливо. Але це не лише через Redux або структуру магазину. Це пояснюється поєднанням незмінного сховища даних, тесту порівняння порівняння змін даних та чистого селектора, який отримує дані, потрібні компоненту, у форматі, який він потребує.
Себастьян Даніель

Привіт, @SebastienDaniel, не могли б ви показати приклад того, як ви реалізуєте перевірку, що кожен компонент знає, чи є зміна оновлення магазину? Я маю на увазі, якщо ви використовуєте якусь загальну модель ... або якщо у кожному конкретному випадку ви перевіряєте, чи змінилися дані, що стосуються конкретних компонентів.
Джон Бернарссон

Відповіді:


232

Існують крайні випадки, коли ви можете використовувати кілька магазинів (наприклад, якщо у вас є проблеми з роботою з оновленням списків тисяч предметів, які одночасно відображаються на екрані багато разів на секунду). Це сказав, що це виняток, і в більшості додатків вам ніколи не потрібно більше, ніж один магазин.

Чому ми наголошуємо на цьому в документах? Оскільки більшість людей, що надходять з фонового режиму Flux, вважають, що кілька магазинів є рішенням зробити код оновлення модульним. Однак Redux має інше рішення для цього: редукторний склад.

Наявність декількох редукторів, які надалі розбиваються на дерево скорочення, - це те, як ви зберігаєте оновлення модульними в Redux. Якщо ви цього не розпізнаєте і не сходите до кількох магазинів, не спочатку розуміючи склад редуктора, ви втратите багато переваг архітектури одного магазину Redux:

  • Використання композиції редуктора дозволяє легко здійснити "залежні оновлення" a la waitForв Flux, записавши редуктор вручну, викликаючи інші редуктори з додатковою інформацією та в певному порядку.

  • З одним магазином можна дуже просто зберігати, гідратирувати та читати стан. Візуалізація сервера та попереднє завантаження даних є тривіальним, оскільки існує лише одне сховище даних, яке потрібно заповнити та повторно зневоднити на клієнті, і JSON може описати його вміст, не турбуючись про ідентифікатор або назву магазину.

  • Один магазин робить можливими функції подорожі в часі Redux DevTools. Це також робить розширення спільноти на зразок redux-скасування або оптимістичні для скорочення просто, оскільки вони працюють на рівні скорочення. Такі "підсилювачі редукторів" не можна писати для магазинів.

  • Один магазин гарантує, що підписки будуть викликані лише після обробки відправки. Тобто до моменту повідомлення слухачів стан було повністю оновлено. У багатьох магазинах таких гарантій немає. Це одна з причин, що Flux потребує waitForмилицю. З одним магазином це не проблема, яку ви бачите в першу чергу.

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


11
Я визнаю, що не зрозумів усієї переваги / необхідності редукторного складу. Завдяки вашій відповіді я ще трохи прочитав та приклад (TodoMVC, знову). З таким невеликим прикладом було важко зрозуміти фактичне поліпшення, що забезпечується редукторним складом. Однак, задумавшись, у великому масштабі виграш (зараз) очевидний. Ще раз дякую, чудова відповідь!
Себастьян Даніель

4
@Sebastien Приклад "кошик" краще для цього я думаю.
Дан Абрамов

3
Я повільно впроваджую функцію redux у традиційну (не SPA) програму. Я використовую магазини мультільпе для кожного "цілого", який я перетворюю на реагування / скорочення, поки весь додаток не може бути змінено на використання одного і того ж магазину.
Пол Кнопф

5
@DanAbramov Цікаво, що ви б взяли за ситуацію, коли у вас є основний "додаток", який працює у власному магазині Redux та імпортує через npm самостійний "додаток", який працює з власним окремим магазином Redux. Наприклад, якщо одна з інших команд вашої компанії має якусь послугу обміну повідомленнями з інтерфейсом користувача, який ви бажаєте отримати, не забруднюючи ваш магазин цими даними.
natlee75

6
@ natlee75 "Деякі обґрунтовані причини використання кількох магазинів у Redux можуть включати: [...] Виділення програми Redux як компонента у більшій програмі. У цьому випадку ви можете створити магазин за екземпляром компонента root." Із redux.js.org/docs/FAQ.html#store-setup-multiple-stores
Кевін

24

У деяких дуже великих корпоративних додатках із сотнями чи тисячами редукторів часто корисно думати про різні області програми як про зовсім окремі додатки. У тих випадках (де насправді є кілька додатків, які мають спільне ім’я домену), я використовую кілька магазинів.

Наприклад, я схильний розглядати такі спільні області функціональності як окремі додатки:

  • Адміністратор
  • Аналітика / дані на інформаційних панелях
  • Управління рахунками та потоки придбання
  • Команда / управління дозволом підприємства

Якщо будь-яка з цих речей невелика, просто збережіть їх як частину основного додатка. Якщо вони зростають дуже великими (як це роблять деякі інструменти управління обліковими записами підприємств та аналітичними засобами), розділіть їх.

Найкращий спосіб керувати дуже великими програмами - це ставитися до них як до складу багатьох менших додатків.

Якщо ваш додаток менше, ніж скажімо, - 50 кВт LOC, ви, ймовірно, повинні проігнорувати цю пораду та дотримуватися порад Дана, замість цього.

Якщо ваш додаток перевищує 1 мільйон LOC, вам, ймовірно, слід розділити міні-додатки, навіть якщо ви підтримуєте їх у моно-репо.


5

Це архітектурне рішення належить розробникам додатків на основі потреб їх проектів

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

  • Це не є надійним, оскільки частини магазину не є ізольованими.
  • Це неефективно, тому що ви клонуєте та обміняєте хеш-трі. Коли мутації зростають арифметично - складність зростає геометрично. Ви не змогли це виправити, переробляючи будь-які редуктори, селектори тощо. Ви повинні розділити трійку.
  • Коли він стає повільним, ніхто не хоче розділяти його на окремі програми з окремими магазинами. Ніхто не хоче витрачати гроші на рефакторинг. Люди зазвичай перетворюють деякі розумні компоненти в дамп, і це все. Чи знаєте ви, яке майбутнє чекає на розробників скорочення? Вони будуть підтримувати ці пекло.
  • Це не дружнє налагодження . Важко налагоджувати зв’язки між практично ізольованими частинами магазину. Дуже важко навіть проаналізувати кількість цих зв’язків.

Давайте уявимо, що у вас є кілька магазинів редукції. Ви порушите однонаправлений потік даних. Ви відразу зрозумієте, скільки у вас зв’язків між магазинами. Ви можете постраждати від цих зв’язків, бореться з круговими депами тощо.

Одномісний непорушний склад з односпрямованим потоком - це не еліксир для кожної хвороби. Якщо ви не хочете підтримувати архітектуру проекту, ви все одно постраждаєте.


Мені сподобалось те, що ти сказав, і тут я поставив відповідне запитання з цього приводу. Чи не заперечуєте ви на це, коли загляньте трохи часу і поділіться своєю думкою? Питання, яке я задав у Reddit, оскільки ТАК не заохочує таких питань тут.
Arup Rakshit

3

Кілька магазинів можуть бути корисними у наступних випадках використання 1. Якщо у вас є великі компоненти, незалежні один від одного за структурою даних, поведінкою, контекстом програми. Виділення цих компонентів полегшує управління вашими потоками даних та додатків. Це також допомагає незалежній розробці та обслуговуванню ваших компонентів. 2. Проблеми з продуктивністю: не типовий випадок використання, але якщо деякі ваші компоненти оновлюються дуже часто і не впливають на інші компоненти, ймовірно, ви можете піти в різні магазини.

Для всіх інших випадків вам може не знадобитися кілька магазинів. Як каже Ден, створення продуманих композицій редукторів може виявитися кращим рішенням.


Ваше повідомлення виглядає як "використовувати надмір завжди, за винятком кількох випадків" == "Вам не потрібна архітектура проекту, крім кількох випадків". Це дуже близько до реальності, я щасливий.
пучу

2

чому ми не можемо скористатися кількома магазинами за допомогою redux ????

У Redux це не потрібно, оскільки розділення між доменами даних вже досягається розщепленням одного редуктора на менші редуктори.


Чи можу я чи мушу створювати кілька магазинів? Чи можу я імпортувати свій магазин безпосередньо та використовувати його в компонентах самостійно?

Оригінальний шаблон Flux описує наявність декількох "магазинів" у додатку, кожен з яких містить іншу область даних домену. Це може призвести до таких проблем, як необхідність мати один магазин "waitFor" інший магазин для оновлення.

У Redux це не потрібно, оскільки розділення між доменами даних вже досягається розщепленням одного редуктора на менші редуктори.

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

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

Вирішення проблеми ефективності, спричинене занадто частими оновленнями певної частини штату, підтверджене профілюванням програми. Виділення програми Redux як компонента в більшій програмі, і в цьому випадку ви можете створити магазин для кожного екземпляра кореневого компонента. Однак створення нових магазинів не повинно бути вашим першим інстинктом, особливо якщо ви робите Flux. Спробуйте спочатку склад редуктора і використовуйте лише кілька магазинів, якщо це не вирішує вашу проблему.

Так само, хоча ви можете посилатися на екземпляр свого магазину, імпортуючи його безпосередньо, це не рекомендований зразок у Redux. Якщо ви створите екземпляр магазину та експортуєте його з модуля, він стане одинаковим. Це означає, що складніше буде виділити додаток Redux як компонент більшого додатка, якщо це коли-небудь необхідно, або включити надання сервера, оскільки на сервері ви хочете створити окремі екземпляри магазину для кожного запиту.

офіційний doc by redux


1

Маючи один магазин в Redux - це дійсно те, що нам потрібно в багатьох випадках, і я використовував Redux і Flux і вважаю, що Redux робить цю роботу краще!

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

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

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


3
Тож усі повинні вірити, що один магазин зробить роботу краще, і ніхто не міг пояснити, чому. Це мені щось нагадує ...
puchu
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.