Redux: più negozi, perché no?


221

Come nota: ho letto i documenti per Redux (anche Baobab) e ho fatto una buona parte di Google e test.

Perché è così fortemente suggerito che un'app Redux abbia un solo negozio?

Comprendo i pro / contro di una configurazione a negozio singolo rispetto a una configurazione a negozio multiplo ( ci sono molte domande e risposte su SO su questo argomento ).

IMO, questa decisione architettonica appartiene agli sviluppatori di app in base alle esigenze dei loro progetti. Allora perché è così fortemente suggerito per Redux, quasi al punto di sembrare obbligatorio ( anche se nulla ci impedisce di creare più negozi )?

EDIT: feedback dopo la conversione in negozio singolo

Dopo alcuni mesi di lavoro con Redux su ciò che molti considererebbero una SPA complessa, posso dire che la struttura del singolo negozio è stata una vera delizia con cui lavorare.

Alcuni punti che potrebbero aiutare gli altri a capire perché un singolo negozio contro molti negozi è una domanda controversa in molti, molti casi d'uso:

  • è affidabile : utilizziamo i selettori per esaminare lo stato dell'app e ottenere informazioni pertinenti al contesto. Sappiamo che tutti i dati necessari si trovano in un unico negozio. Evita ogni dubbio su dove potrebbero essere i problemi di stato.
  • è veloce : il nostro negozio ha attualmente quasi 100 riduttori, se non di più. Anche a quel punto, solo una manciata di riduttori elabora i dati su una determinata spedizione, gli altri restituiscono semplicemente lo stato precedente. L'argomento secondo cui un negozio enorme / complesso (numero di riduttori ) è lento è praticamente discutibile. Almeno non abbiamo visto alcun problema di prestazioni proveniente da lì.
  • debugging amichevole : mentre questo è un argomento molto convincente per usare il redux nel suo insieme, vale anche per un singolo negozio contro più negozi. Quando si crea un'app, si è tenuti ad avere errori di stato nel processo ( errori del programmatore ), è normale. Il PITA è quando quegli errori impiegano ore per il debug. Grazie al singolo negozio ( e redux-logger ) non abbiamo mai trascorso più di qualche minuto su un dato problema di stato.

alcuni suggerimenti

La vera sfida nella costruzione del tuo negozio redux è quando decidi come strutturarlo . Innanzitutto, perché cambiare la struttura lungo la strada è solo un grande dolore. In secondo luogo, perché determina in gran parte il modo in cui verrà utilizzato e l'interrogazione dei dati dell'app per qualsiasi processo. Ci sono molti suggerimenti su come strutturare un negozio. Nel nostro caso abbiamo trovato quanto segue ideale:

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

Spero che questo feedback possa aiutare gli altri.

EDIT 2 - utili strumenti di archiviazione

Per quelli di voi che si sono chiesti come "gestire" facilmente un singolo negozio , che può diventare rapidamente complesso. Esistono strumenti che aiutano a isolare le dipendenze strutturali / la logica del tuo negozio.

C'è Normalizr che normalizza i tuoi dati in base a uno schema. Fornisce quindi un'interfaccia per lavorare con i tuoi dati e recuperare altre parti dei tuoi dati id, proprio come un dizionario.

Non sapendo Normalizr al momento, ho costruito qualcosa seguendo le stesse linee. relational-json accetta uno schema e restituisce un'interfaccia basata su tabella ( un po 'come un database ). Il vantaggio di relational-json è che la struttura dei dati fa riferimento dinamicamente ad altre parti dei dati (in sostanza, è possibile attraversare i dati in qualsiasi direzione, proprio come i normali oggetti JS ). Non è maturo come Normalizr, ma lo uso con successo nella produzione da alcuni mesi.


4
Mi piace il tuo approccio per la struttura del negozio che stai utilizzando; tuttavia, come gestite il mapping delle modifiche dello stato dell'API alle modifiche dello stato del componente? Quindi supponiamo che riceva dati specifici del dominio dalla mia API, come si traduce in una struttura di dati generica che si troverebbe nei miei componenti?
Diniden,

Il modo in cui i componenti mappano / utilizzano i dati del negozio dipende davvero da te. Anche se penso di non comprendere appieno la tua domanda, potresti elaborare o avviare una sessione di chat?
Sebastien Daniel,

2
Immagino che la domanda sarebbe: rendere i tuoi componenti renderizzati dallo stato di apis o renderanno solo tutto ciò che viene messo nello stato dei componenti. Sospetterei se riuscissi a eseguire il SOLO rendering dallo stato del componente, quindi hai trovato un modo eccellente per rendere i tuoi componenti e container altamente riutilizzabili anche in presenza di dati specifici del dominio. Se i componenti vengono renderizzati parzialmente dallo stato dell'API E dallo stato dei componenti, allora suppongo che tu stia utilizzando Contenitori specifici del dominio per mappare i dati in api su elenchi e primitive generici che i tuoi componenti comprendono.
Diniden,

2
Uso Redux insieme ai selettori, che sono fondamentalmente mappatori di dati funzionalmente puramente memorizzati. Ogni componente "reagisce" per archiviare gli aggiornamenti e, se una modifica è pertinente, "seleziona" i dati e li rende di conseguenza. Quindi sì, i componenti vengono visualizzati SOLO in base a ciò che conta per loro. Ma questo non è solo a causa di Redux o della struttura del negozio. È dovuto alla combinazione di un archivio di dati immutabili, un test di confronto referenziale per le modifiche ai dati e un selettore puro che recupera i dati di cui il componente ha bisogno, nel formato di cui ha bisogno.
Sebastien Daniel,

Ehi @SebastienDaniel, potresti mostrare un esempio di come stai implementando il controllo che ogni componente fa per sapere se la modifica dell'aggiornamento del negozio è pertinente? Voglio dire se stai usando un qualche tipo di modello generico ... o se in ogni caso specifico stai controllando se i dati relativi al componente specifico sono cambiati.
John Bernardsson,

Risposte:


232

Ci sono casi limite in cui è possibile utilizzare più negozi (ad esempio se si verificano problemi di prestazioni con l'aggiornamento di elenchi di migliaia di articoli che sono sullo schermo contemporaneamente più volte al secondo). Detto questo è un'eccezione e nella maggior parte delle app non hai mai bisogno di più di un singolo negozio.

Perché lo sottolineiamo nei documenti? Poiché la maggior parte delle persone provenienti da background Flux suppone che più negozi sia la soluzione per rendere modulare il codice di aggiornamento. Tuttavia Redux ha una soluzione diversa per questo: composizione del riduttore.

Avere più riduttori che sono ulteriormente suddivisi in un albero dei riduttori è come mantenere gli aggiornamenti modulari in Redux. Se non lo riconosci e vai in più negozi senza prima comprendere a fondo la composizione del riduttore, perderai molti vantaggi dell'architettura Redux a negozio singolo:

  • L'uso della composizione del riduttore semplifica l'implementazione di "aggiornamenti dipendenti" waitForalla Flux scrivendo un riduttore chiamando manualmente altri riduttori con informazioni aggiuntive e in un ordine specifico.

  • Con un singolo negozio, è molto facile persistere, idratare e leggere lo stato. Il rendering del server e il prefetching dei dati sono banali perché esiste solo un archivio dati che deve essere riempito e reidratato sul client e JSON può descriverne il contenuto senza preoccuparsi dell'ID o del nome del negozio.

  • Un unico negozio rende possibili le funzionalità di viaggio nel tempo di Redux DevTools. Inoltre semplifica le estensioni della community come redux-undo o redux-optimist perché operano a livello di riduttore. Tali "esaltatori di riduttori" non possono essere scritti per i negozi.

  • Un singolo negozio garantisce che gli abbonamenti vengano chiamati solo dopo l'elaborazione della spedizione. Cioè, al momento della notifica degli ascoltatori, lo stato è stato completamente aggiornato. Con molti negozi non esistono garanzie del genere. Questo è uno dei motivi per cui Flux ha bisogno della waitForstampella. Con un singolo negozio, questo non è un problema che si vede in primo luogo.

  • Soprattutto, in Redux non sono necessari più negozi (ad eccezione dei casi limite di prestazioni che dovresti comunque profilare prima). Lo rendiamo un punto importante nei documenti, quindi sei incoraggiato a imparare la composizione del riduttore e altri schemi Redux invece di usare Redux come se fosse Flux e perdere i suoi benefici.


11
Devo ammettere che non ho capito appieno il vantaggio / la necessità della composizione del riduttore. Grazie alla tua risposta, ho fatto ancora qualche lettura e un esempio (TodoMVC, di nuovo). Con un esempio così piccolo, è stato difficile comprendere l'effettivo miglioramento fornito dalla composizione del riduttore. Tuttavia, con un po 'di pensiero, su larga scala il guadagno è (ora) ovvio. Grazie ancora, ottima risposta!
Sebastien Daniel,

4
@Sebastien L'esempio del "carrello" è meglio per questo, credo.
Dan Abramov,

3
Sto lentamente implementando il redux in un'applicazione tradizionale (non SPA). Sto usando negozi multilpe per ogni "intero" che converto in un'implementazione di reazione / redux fino a quando l'intera app può essere modificata per utilizzare lo stesso negozio.
Paul Knopf,

5
@DanAbramov Curioso quale sarebbe il tuo punto di vista in una situazione in cui hai la tua "app" principale che esegue il proprio negozio Redux e importa tramite npm una "app" autonoma che gestisce il proprio negozio Redux separato. Ad esempio, se uno degli altri team della tua azienda ha una sorta di servizio di messaggistica con un'interfaccia utente che desideri richiamare senza inquinare il tuo negozio con quei dati.
natlee75,

6
@ natlee75 "Alcuni validi motivi per utilizzare più negozi in Redux potrebbero includere: [...] Isolamento di un'app Redux come componente in un'applicazione più grande, nel qual caso potresti voler creare un negozio per istanza del componente radice." Da redux.js.org/docs/FAQ.html#store-setup-multiple-stores
Kevin

24

In alcune app aziendali di grandi dimensioni con centinaia o migliaia di riduttori, è spesso utile pensare a diverse aree dell'app come app completamente separate. In quei casi (dove sono davvero più app che condividono un nome di dominio), utilizzo più negozi.

Ad esempio, tendo a trattare le seguenti aree di funzionalità comuni come app separate:

  • Admin
  • Analisi / dati su dashboard
  • Gestione della fatturazione e flussi di acquisto
  • Team account aziendale / gestione autorizzazioni

Se una di queste cose è piccola, tienila come parte dell'app principale. Se diventano molto grandi (come fanno alcuni strumenti di gestione e analisi degli account aziendali), suddividili.

Il modo migliore per gestire app di grandi dimensioni è trattarle come una composizione di molte app più piccole.

Se la tua app è inferiore a ~ 50k LOC, dovresti probabilmente ignorare questo consiglio e seguire invece il consiglio di Dan.

Se la tua app è superiore a 1 milione di LOC, dovresti probabilmente suddividere le mini-app, anche se le mantieni in un repository mono.


5

Questa decisione architettonica appartiene agli sviluppatori di app in base alle esigenze dei loro progetti

Stai vivendo nel tuo mondo. Sto incontrando persone che usano il redux, perché è popolare, ogni giorno. Non puoi nemmeno immaginare quanti progetti sono stati avviati in fase di ristrutturazione senza alcuna decisione. Odio gli approcci redux ma ho dovuto usarlo, perché altri sviluppatori non sanno nient'altro. È solo una bolla epica gonfiata da Facebook.

  • Non è affidabile perché parti del negozio non sono isolate.
  • È inefficiente perché stai clonando e attraversando l'hash trie. Quando le mutazioni crescono aritmeticamente, la complessità cresce geometricamente. Non è stato possibile ripararlo rifattorizzando riduttori, selettori, ecc. È necessario dividere il trie.
  • Quando diventa lento nessuno vuole dividerlo in applicazioni separate con negozi separati. Nessuno vuole spendere soldi per il refactoring. Le persone lo sono di solito convertono alcuni componenti intelligenti in discarica e basta. Sai quale futuro sta aspettando gli sviluppatori di redux? Manterranno questi inferni.
  • Non è facile eseguire il debug . È difficile eseguire il debug delle connessioni tra parti del negozio praticamente isolate. È molto difficile persino analizzare la quantità di queste connessioni.

Immaginiamo di avere diversi negozi redux. Interromperai il flusso di dati unidirezionale. Ti renderai immediatamente conto di quante connessioni hai tra i negozi. Puoi soffrire di queste connessioni, combattendo con avvallamenti circolari, ecc.

Un singolo negozio immutabile con flusso unidirezionale non è un elisir per ogni malattia. Se non vuoi mantenere l'architettura del progetto, soffrirai comunque.


Mi è piaciuto quello che hai detto, e qui ho posto una domanda correlata su questo. Ti dispiacerebbe guardarlo quando avrai del tempo e condividi le tue opinioni? La domanda che ho posto in Reddit, perché SO non incoraggia tali domande qui.
Arup Rakshit,

3

Più negozi possono essere utili nei seguenti casi d'uso 1. Se si dispone di componenti di grandi dimensioni indipendenti l'uno dall'altro in termini di struttura dei dati, comportamento, contesto dell'applicazione. L'isolamento di questi componenti semplifica la gestione dei flussi di dati e applicazioni. Inoltre aiuta lo sviluppo e la manutenzione indipendenti dei componenti. 2. Problemi di prestazioni: non un tipico caso d'uso, ma se alcuni dei tuoi componenti si aggiornano molto frequentemente e non hanno alcun impatto su altri componenti, probabilmente puoi andare in diversi negozi.

Per tutti gli altri casi, potrebbe non essere necessario disporre di più negozi. Come dice Dan, la creazione di composizioni ridotte ponderate può rivelarsi la soluzione migliore.


Il tuo messaggio sembra "usa redux sempre tranne pochi casi" == "non hai bisogno dell'architettura di progetto tranne pochi casi". È molto vicino alla realtà, sono felice.
puchu

2

perché non possiamo usare più negozi usando redux ????

Ciò non è necessario in Redux perché la separazione tra domini di dati è già ottenuta suddividendo un singolo riduttore in riduttori più piccoli.


Posso o devo creare più negozi? Posso importare direttamente il mio negozio e usarlo nei componenti da solo?

Il modello Flux originale descrive la presenza di più "store" in un'app, ognuno contenente una diversa area di dati di dominio. Ciò può comportare problemi come la necessità di avere un negozio "waitFor" per aggiornare un altro negozio.

Ciò non è necessario in Redux perché la separazione tra domini di dati è già ottenuta suddividendo un singolo riduttore in riduttori più piccoli.

Come per molte altre domande, è possibile creare più negozi Redux distinti in una pagina, ma lo schema previsto è avere un solo negozio. La presenza di un singolo negozio consente di utilizzare Redux DevTools, semplifica la persistenza e la reidratazione dei dati e semplifica la logica di abbonamento.

Alcuni motivi validi per l'utilizzo di più negozi in Redux potrebbero includere:

Risolvere un problema di prestazioni causato da aggiornamenti troppo frequenti di alcune parti dello stato, quando confermato dalla creazione del profilo dell'app. Isolamento di un'app Redux come componente in un'applicazione più grande, nel qual caso potresti voler creare un negozio per istanza del componente radice. Tuttavia, la creazione di nuovi negozi non dovrebbe essere il tuo primo istinto, soprattutto se provieni da un background Flux. Prova prima la composizione del riduttore e usa più negozi solo se non risolve il tuo problema.

Allo stesso modo, mentre puoi fare riferimento all'istanza del tuo negozio importandolo direttamente, questo non è uno schema raccomandato in Redux. Se crei un'istanza del negozio ed esporti da un modulo, diventerà un singleton. Ciò significa che sarà più difficile isolare un'app Redux come componente di un'app più grande, se necessario, o per abilitare il rendering del server, perché sul server si desidera creare istanze store separate per ogni richiesta.

doc ufficiale di redux


1

Avere un negozio a Redux è davvero ciò di cui abbiamo bisogno in molti casi, entrambi ho usato Redux e Flux e credo che Redux svolga meglio il suo lavoro!

Non dimenticare che il negozio si trova in un oggetto JavaScript, quindi mentre hai un solo negozio, può essere facilmente esteso e riutilizzato, per me, avere un negozio rende molto più facile attraversare utilizzando gli strumenti di sviluppo Redux e non essere confuso in grandi applicazioni ...

Anche il concetto di un negozio sta imitando il database per noi, una fonte di verità che puoi modificarlo e puoi accedervi nella memoria del browser ...

Se l'intera applicazione è ben gestita, un negozio può essere sufficiente per gestire l'intero stato dell'applicazione ...


3
Quindi tutti dovrebbero credere che il singolo negozio farà un lavoro migliore e nessuno potrebbe spiegare il perché. Mi ricorda qualcosa ...
puchu
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.