Redux - plusieurs magasins, pourquoi pas?

221

Remarque: j'ai lu les documents pour Redux (Baobab aussi) et j'ai fait une bonne partie de Google et des tests.

Pourquoi est-il si fortement suggéré qu'une application Redux n'ait qu'un seul magasin?

Je comprends les avantages / inconvénients d'une configuration à magasin unique par rapport à une configuration à magasins multiples ( il existe de nombreuses questions / réponses sur SO à ce sujet ).

IMO, cette décision architecturale appartient aux développeurs d'applications en fonction des besoins de leurs projets. Alors pourquoi est-il si fortement suggéré pour Redux, presque au point de paraître obligatoire ( bien que rien ne nous empêche de faire plusieurs magasins )?

EDIT: rétroaction après la conversion en magasin unique

Après quelques mois de travail avec Redux sur ce que beaucoup considéreraient comme un SPA complexe, je peux dire que la structure à magasin unique a été un pur plaisir de travailler avec.

Quelques points qui pourraient aider les autres à comprendre pourquoi le magasin unique par rapport à plusieurs magasins est une question théorique dans de nombreux cas d'utilisation:

  • il est fiable : nous utilisons des sélecteurs pour parcourir l'état de l'application et obtenir des informations contextuelles. Nous savons que toutes les données nécessaires se trouvent dans un seul magasin. Cela évite toute remise en question de la situation des problèmes d'État.
  • c'est rapide : notre magasin compte actuellement près de 100 réducteurs, sinon plus. Même à ce niveau, seule une poignée de réducteurs traitent les données sur une répartition donnée, les autres renvoient simplement l'état précédent. L'argument selon lequel un magasin énorme / complexe ( nombre de réducteurs ) est lent est à peu près théorique. Au moins, nous n'avons vu aucun problème de performance en provenance de là.
  • débogage convivial : bien que ce soit un argument le plus convaincant pour utiliser redux dans son ensemble, il vaut également pour le magasin unique contre le magasin multiple. Lorsque vous créez une application, vous êtes lié à des erreurs d'état dans le processus ( erreurs de programmation ), c'est normal. Le PITA est lorsque ces erreurs mettent des heures à déboguer. Grâce au magasin unique ( et au redux-logger ), nous n'avons jamais passé plus de quelques minutes sur un problème d'état donné.

quelques conseils

Le vrai défi dans la construction de votre magasin redux est de décider comment le structurer . Tout d'abord, parce que changer de structure en cours de route n'est qu'une douleur majeure. Deuxièmement, car cela détermine en grande partie comment vous allez utiliser et interroger les données de votre application pour n'importe quel processus. Il existe de nombreuses suggestions sur la façon de structurer un magasin. Dans notre cas, nous avons trouvé que ce qui suit était idéal:

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

J'espère que ces commentaires aideront les autres.

EDIT 2 - outils de magasin utiles

Pour ceux d'entre vous qui se demandent comment gérer "facilement" un seul magasin , ce qui peut rapidement devenir complexe. Il existe des outils qui aident à isoler les dépendances structurelles / la logique de votre magasin.

Il y a Normalizr qui normalise vos données en fonction d'un schéma. Il fournit ensuite une interface pour travailler avec vos données et récupérer d'autres parties de vos données id, un peu comme un dictionnaire.

Ne connaissant pas Normalizr à l'époque, j'ai construit quelque chose dans le même sens. relationnel-json prend un schéma et renvoie une interface basée sur une table ( un peu comme une base de données ). L'avantage de relation-json est que votre structure de données référence dynamiquement d'autres parties de vos données ( essentiellement, vous pouvez parcourir vos données dans n'importe quelle direction, tout comme les objets JS normaux ). Ce n'est pas aussi mature que Normalizr, mais je l'utilise avec succès en production depuis quelques mois maintenant.

Sébastien Daniel
la source
4
J'aime votre approche de la structure du magasin que vous utilisez; cependant, comment gérez-vous le mappage des changements d'état de l'API avec les changements d'état de vos composants? Donc, disons que je reçois des données spécifiques à un domaine de mon API, comment cela se traduit-il en une structure de données générique qui se trouverait dans mes composants?
Diniden
La façon dont vos composants mappent / utilisent les données du magasin dépend vraiment de vous. Bien que je pense que je ne comprends pas bien votre question, pourriez-vous élaborer ou démarrer une session de chat?
Sebastien Daniel
2
Je suppose que la question serait: est-ce que vos composants rendent tout à partir de l'état apis, ou ne rendent-ils que ce qui est mis dans l'état des composants. Je soupçonne que si vous parvenez à effectuer un rendu UNIQUEMENT à partir de l'état du composant, vous avez trouvé un excellent moyen de rendre vos composants et conteneurs hautement réutilisables, même en présence de données spécifiques au domaine. Si vos composants sont rendus partiellement à partir de l'état de l'API ET de l'état des composants, je suppose que vous utilisez des conteneurs spécifiques au domaine pour mapper les données dans les API à des listes génériques et des primitives que vos composants comprennent.
Diniden
2
J'utilise Redux en conjonction avec des sélecteurs, qui sont essentiellement des mappeurs de données fonctionnellement purs. Chaque composant "réagit" pour stocker les mises à jour, et si un changement est pertinent, il "sélectionne" les données et les rend en conséquence. Alors oui, les composants ne sont rendus qu'en fonction de ce qui compte pour eux. Mais ce n'est pas seulement à cause de Redux ou de la structure du magasin. Cela est dû à la combinaison d'un magasin de données immuable, d'un test de comparaison référentielle pour les modifications de données et d'un pur sélecteur qui récupère les données dont le composant a besoin, dans le format dont il a besoin.
Sebastien Daniel
Hé @SebastienDaniel, pourriez-vous montrer un exemple de la façon dont vous implémentez la vérification que chaque composant fait pour savoir si le changement dans la mise à jour du magasin est pertinent pour lui? Je veux dire si vous utilisez une sorte de modèle générique ... ou si dans chaque cas spécifique vous vérifiez si les données spécifiques aux composants ont changé.
John Bernardsson

Réponses:

232

Il existe des cas extrêmes où vous pouvez utiliser plusieurs magasins (par exemple, si vous avez des problèmes de performances avec la mise à jour de listes de milliers d'éléments qui sont à l'écran en même temps plusieurs fois par seconde). Cela dit, c'est une exception et dans la plupart des applications, vous n'avez jamais besoin de plus d'un seul magasin.

Pourquoi insistons-nous sur cela dans les documents? Parce que la plupart des gens venant de l'arrière-plan de Flux supposeront que plusieurs magasins sont la solution pour rendre le code de mise à jour modulaire. Cependant, Redux a une solution différente pour cela: la composition du réducteur.

Avoir plusieurs réducteurs qui sont encore divisés en une arborescence de réducteurs est la façon dont vous gardez les mises à jour modulaires dans Redux. Si vous ne le reconnaissez pas et optez pour plusieurs magasins sans comprendre d'abord la composition du réducteur, vous manquerez de nombreux avantages de l'architecture de magasin unique Redux:

  • L'utilisation de la composition du réducteur facilite la mise en œuvre de «mises à jour dépendantes» à la manière waitForde Flux en écrivant un réducteur appelant manuellement d'autres réducteurs avec des informations supplémentaires et dans un ordre spécifique.

  • Avec un seul magasin, il est très facile de persister, de s'hydrater et de lire l'état. Le rendu du serveur et la prélecture des données sont triviaux car il n'y a qu'un seul stockage de données qui doit être rempli et réhydraté sur le client, et JSON peut décrire son contenu sans se soucier de l'ID ou du nom du magasin.

  • Un seul magasin rend possible les fonctionnalités de voyage dans le temps de Redux DevTools. Cela facilite également les extensions de communauté comme redux-undo ou redux-optimist car elles fonctionnent au niveau du réducteur. De tels "amplificateurs de réduction" ne peuvent pas être écrits pour les magasins.

  • Un magasin unique garantit que les abonnements ne sont appelés qu'après le traitement de l'envoi. Autrement dit, au moment où les auditeurs sont informés, l'état a été entièrement mis à jour. Avec de nombreux magasins, il n'y a pas de telles garanties. C'est l'une des raisons pour lesquelles Flux a besoin de la waitForbéquille. Avec un seul magasin, ce n'est pas un problème que vous voyez en premier lieu.

  • Surtout, plusieurs magasins ne sont pas nécessaires dans Redux (sauf pour les cas de performances que vous êtes censé profiler en premier de toute façon). Nous en faisons un point important dans la documentation, vous êtes donc encouragé à apprendre la composition du réducteur et d'autres modèles Redux au lieu d'utiliser Redux comme s'il s'agissait de Flux et de perdre ses avantages.

Dan Abramov
la source
11
J'admets que je n'ai pas compris le plein avantage / nécessité de la composition du réducteur. Grâce à votre réponse, j'ai fait un peu plus de lecture et un exemple (TodoMVC, encore). Avec un si petit exemple, il était difficile de comprendre l'amélioration réelle apportée par la composition du réducteur. Cependant, avec un peu de réflexion, à grande échelle, le gain est (maintenant) évident. Merci encore, excellente réponse!
Sebastien Daniel
4
@Sebastien L'exemple du "panier" est mieux pour cela je pense.
Dan Abramov
3
J'implémente lentement redux dans une application traditionnelle (non SPA). J'utilise des magasins multilpe pour chaque "ensemble" que je convertis en implémentation react / redux jusqu'à ce que l'application entière puisse être modifiée pour utiliser le même magasin.
Paul Knopf
5
@DanAbramov Curieux de savoir ce que vous pensez d'une situation où votre "application" principale gère son propre magasin Redux et importe via npm une "application" autonome qui gère son propre magasin Redux distinct. Par exemple, si l'une des autres équipes de votre entreprise dispose d'une sorte de service de messagerie avec une interface utilisateur que vous souhaitez utiliser sans polluer votre magasin avec ces données.
natlee75
6
@ natlee75 "Voici quelques raisons valables d'utiliser plusieurs magasins dans Redux: [...] Isoler une application Redux en tant que composant dans une application plus grande, auquel cas vous souhaiterez peut-être créer un magasin par instance de composant racine." De redux.js.org/docs/FAQ.html#store-setup-multiple-stores
Kevin
24

Dans certaines très grandes applications d'entreprise avec des centaines ou des milliers de réducteurs, il est souvent utile de considérer les différents domaines de l'application comme des applications entièrement distinctes. Dans ces cas (où il s'agit vraiment de plusieurs applications qui partagent un nom de domaine), j'utilise plusieurs magasins.

Par exemple, j'ai tendance à traiter les domaines de fonctionnalité courants suivants comme des applications distinctes:

  • Admin
  • Tableaux de bord Analytics / data vis
  • Gestion de la facturation et flux d'achat
  • Équipe de compte d'entreprise / gestion des autorisations

Si l'une de ces choses est petite, conservez-la simplement dans l'application principale. S'ils deviennent très importants (comme le font certains outils de gestion de compte d'entreprise et d'analyse), séparez-les.

La meilleure façon de gérer de très grandes applications est de les traiter comme une composition de nombreuses petites applications.

Si votre application est inférieure à environ 50k LOC, vous devriez probablement ignorer ce conseil et suivre les conseils de Dan à la place.

Si votre application est supérieure à 1 million de LOC, vous devriez probablement diviser les mini-applications, même si vous les conservez dans un référentiel mono.

Eric Elliott
la source
5

Cette décision architecturale appartient aux développeurs d'applications en fonction des besoins de leurs projets

Vous vivez dans votre propre monde. Je rencontre des gens qui utilisent redux, car c'est populaire, tous les jours. Vous ne pouviez même pas imaginer combien de projets ont commencé à être redondés sans aucune décision. Je déteste les approches redux mais je devais l'utiliser, car les autres développeurs ne savent rien d'autre. C'est juste une bulle épique gonflée par Facebook.

  • Ce n'est pas fiable car certaines parties du magasin ne sont pas isolées.
  • C'est inefficace car vous clonez et traversez le triage de hachage. Lorsque les mutations se développent arithmétiquement - la complexité croît géométriquement. Vous ne pouvez pas y remédier en refactorisant les réducteurs, les sélecteurs, etc. Vous devez diviser votre trie.
  • Lorsqu'il devient lent, personne ne veut le diviser en applications distinctes avec des magasins distincts. Personne ne veut dépenser de l'argent pour le refactoring. Les gens convertissent généralement certains composants intelligents en vidage et c'est tout. Savez-vous quel avenir attend les développeurs redux? Ils maintiendront ces enfers.
  • Ce n'est pas un débogage convivial . Il est difficile de déboguer les connexions entre des parties virtuellement isolées du magasin. Il est même très difficile d'analyser la quantité de ces connexions.

Imaginons que vous ayez plusieurs magasins redux. Vous interromprez le flux de données unidirectionnel. Vous réaliserez immédiatement combien de connexions vous avez entre les magasins. Vous pouvez souffrir de ces connexions, vous battre avec des députés circulaires, etc.

Un magasin immuable unique avec un flux unidirectionnel n'est pas un élixir pour chaque maladie. Si vous ne voulez pas conserver l'architecture du projet, vous en souffrirez quand même.

puchu
la source
J'ai aimé ce que vous avez dit, et ici j'ai posé une question connexe à ce sujet. Pourriez-vous regarder cela lorsque vous aurez le temps de partager vos opinions? La question que j'ai posée dans Reddit, car SO n'encourage pas de telles questions ici.
Arup Rakshit du
3

Plusieurs magasins peuvent être utiles dans les cas d'utilisation suivants 1. Si vous avez de gros composants indépendants les uns des autres en termes de structure de données, de comportement, de contexte d'application. L'isolement de ces composants facilite la gestion de vos flux de données et d'applications. Il aide également au développement et à la maintenance indépendants de vos composants. 2. Problèmes de performances: pas un cas d'utilisation typique, mais si certains de vos composants sont mis à jour très fréquemment et n'ont aucun impact sur d'autres composants, vous pouvez probablement opter pour différents magasins.

Pour tous les autres cas, vous n'aurez peut-être pas besoin d'avoir plusieurs magasins. Comme le dit Dan, la création de compositions réductrices réfléchies peut s'avérer être une meilleure solution.

newtonflash
la source
Votre message ressemble à "utilisez toujours redux sauf quelques cas" == "vous n'avez pas besoin d'architecture de projet sauf quelques cas". C'est très proche de la réalité, je suis content.
puchu
2

pourquoi nous ne pouvons pas utiliser plusieurs magasins en utilisant redux ????

Cela n'est pas nécessaire dans Redux car la séparation entre les domaines de données est déjà réalisée en divisant un seul réducteur en petits réducteurs.


Puis-je ou dois-je créer plusieurs magasins? Puis-je importer ma boutique directement et l'utiliser moi-même dans des composants?

Le modèle de flux d'origine décrit la présence de plusieurs «magasins» dans une application, chacun contenant une zone différente de données de domaine. Cela peut entraîner des problèmes tels que la nécessité d'avoir un magasin «waitFor» pour un autre magasin à mettre à jour.

Cela n'est pas nécessaire dans Redux car la séparation entre les domaines de données est déjà réalisée en divisant un seul réducteur en petits réducteurs.

Comme pour plusieurs autres questions, il est possible de créer plusieurs magasins Redux distincts dans une page, mais le modèle prévu est de n'avoir qu'un seul magasin. Le fait d'avoir un seul magasin permet d'utiliser les Redux DevTools, rend les données persistantes et réhydratantes plus simples et simplifie la logique d'abonnement.

Certaines raisons valables pour utiliser plusieurs magasins dans Redux peuvent inclure:

Résoudre un problème de performances causé par des mises à jour trop fréquentes d'une partie de l'état, lorsque confirmé par le profilage de l'application. Isoler une application Redux en tant que composant dans une application plus grande, auquel cas vous souhaiterez peut-être créer un magasin par instance de composant racine. Cependant, la création de nouveaux magasins ne devrait pas être votre premier instinct, surtout si vous venez d'un arrière-plan Flux. Essayez d'abord la composition du réducteur et n'utilisez plusieurs magasins que si cela ne résout pas votre problème.

De même, bien que vous puissiez référencer votre instance de magasin en l'important directement, ce n'est pas un modèle recommandé dans Redux. Si vous créez une instance de magasin et l'exportez à partir d'un module, elle deviendra un singleton. Cela signifie qu'il sera plus difficile d'isoler une application Redux en tant que composant d'une application plus grande, si cela est nécessaire, ou d'activer le rendu du serveur, car sur le serveur, vous souhaitez créer des instances de magasin distinctes pour chaque demande.

doc officiel par redux

Rizo
la source
1

Avoir un magasin à Redux est vraiment ce dont nous avons besoin dans de nombreux cas, j'ai utilisé Redux et Flux et je crois que Redux fait mieux le travail!

N'oubliez pas que le magasin est dans un objet JavaScript, donc bien que vous n'ayez qu'un seul magasin, il peut être facilement étendu et réutilisé, pour moi, avoir un magasin le rend beaucoup plus facile à parcourir à l'aide des outils de développement Redux et ne pas être mélangé dans grandes applications ...

De plus, le concept d'un magasin imite la base de données pour nous, une source de vérité que vous pouvez modifier et y accéder dans la mémoire du navigateur ...

Si l'ensemble de l'application est bien géré, un magasin peut suffire pour gérer l'état de l'ensemble de l'application ...

Alireza
la source
3
Donc, tout le monde devrait croire que le magasin unique fera mieux son travail et personne ne pourrait expliquer pourquoi. Cela me rappelle quelque chose ...
puchu