Perché usare Redux su Facebook Flux? [chiuso]


1126

Ho letto questa risposta , riducendo il boilerplate , ho esaminato alcuni esempi di GitHub e ho anche provato un po 'di redux (todo app).

A quanto ho capito, le motivazioni ufficiali di redux doc forniscono vantaggi rispetto alle architetture MVC tradizionali. MA non fornisce una risposta alla domanda:

Perché dovresti usare Redux su Facebook Flux?

È solo una questione di stili di programmazione: funzionale vs non funzionale? O la domanda è nelle abilità / strumenti di sviluppo che seguono l'approccio redux? Forse ridimensionamento? O test?

Ho ragione se dico che il redux è un flusso per le persone che provengono da linguaggi funzionali?

Per rispondere a questa domanda è possibile confrontare la complessità dei punti di motivazione dell'implementazione redux su flux vs redux.

Ecco i punti di motivazione delle motivazioni ufficiali redux doc :

  1. Gestire aggiornamenti ottimistici (a quanto ho capito, non dipende quasi dal 5 ° punto. È difficile implementarlo nel flusso di Facebook? )
  2. Rendering sul server (anche Facebook Flux può fare questo. Qualche vantaggio rispetto a Redux? )
  3. Recupero dei dati prima di eseguire le transizioni del percorso ( Perché non è possibile ottenerlo nel flusso di Facebook? Quali sono i vantaggi? )
  4. Ricarica a caldo ( è possibile con React Hot Reload . Perché abbiamo bisogno di redux? )
  5. Funzionalità Annulla / Ripristina
  6. Qualche altro punto? Come lo stato persistente ...

73
Redux è un'implementazione di "Facebook Flux". Flux non è una libreria o un framework. È semplicemente un'architettura consigliata per le applicazioni Web. Non vedo come sia possibile confrontare un'implementazione concreta con il concetto astratto che l'ha motivata. L'attuazione effettiva di Facebook di un'architettura Flux è Relay e la versione open source è ancora nelle fasi iniziali. facebook.github.io/relay
Charlie Martin,

2
@CharlieMartin Di FB Flux Applico un'applicazione come questa github.com/facebook/flux/tree/master/examples . Il mio progetto attuale è scritto su FB Flux (due FB Flux). Se lo desideri, potresti pensare come architettura Redux su architettura FB Flux.
VB_

2
Ora capisco. Si desidera confrontare l'implementazione Flux di esempio di Facebook con l'implementazione Flux di Redux
Charlie Martin,

13
Relay non è un'implementazione di Flux - Relay / GraphQL è più interessato alla gestione del recupero / query dei dati con il server, mentre Flux si occupa principalmente di strutturare il flusso di dati tra i modelli di dati lato client e i componenti di visualizzazione. Tuttavia, ci sono alcune sovrapposizioni: su Facebook, abbiamo app costruite interamente usando Flux, interamente usando Relay o con entrambi. Un modello che vediamo emergere è quello di consentire a Relay di gestire la maggior parte del flusso di dati per un'applicazione, ma utilizzando Flux store sul lato per gestire un sottoinsieme dello stato dell'applicazione
Hal

Risposte:


1958

Redux autore qui!

Redux non è così diverso da Flux. Nel complesso ha la stessa architettura, ma Redux è in grado di tagliare alcuni angoli di complessità utilizzando la composizione funzionale in cui Flux utilizza la registrazione di callback.

Non c'è una differenza fondamentale in Redux, ma trovo che renda alcune astrazioni più facili, o almeno possibili da implementare, che sarebbe difficile o impossibile da implementare in Flux.

Composizione del riduttore

Prendi, ad esempio, l'impaginazione. Il mio esempio Flux + React Router gestisce l'impaginazione, ma il codice è terribile. Uno dei motivi per cui è orribile è che Flux rende innaturale il riutilizzo delle funzionalità nei negozi. Se due negozi devono gestire l'impaginazione in risposta a diverse azioni, o devono ereditare da un negozio di base comune (male! Ti stai bloccando in un particolare progetto quando usi l'ereditarietà) o chiamare una funzione definita esternamente dall'interno gestore di eventi, che dovrà in qualche modo operare nello stato privato del negozio Flux. Il tutto è disordinato (anche se sicuramente nel regno del possibile).

D'altra parte, con l'impaginazione Redux è naturale grazie alla composizione del riduttore. Si tratta di riduttori fino in fondo, quindi puoi scrivere una fabbrica di riduttori che genera riduttori di impaginazione e quindi utilizzarli nell'albero dei riduttori . La chiave per cui è così facile è perché in Flux i negozi sono piatti, ma in Redux i riduttori possono essere nidificati tramite composizione funzionale, proprio come i componenti di React possono essere nidificati.

Questo modello abilita anche funzioni meravigliose come annulla / ripristina senza codice utente . Riesci a immaginare di collegare Annulla / Ripristina a un'app Flux come due righe di codice? Quasi. Con Redux, lo è ancora, grazie al modello di composizione del riduttore. Devo evidenziare che non c'è nulla di nuovo in questo: questo è il modello sperimentato e descritto in dettaglio in Elm Architecture che è stato a sua volta influenzato da Flux.

Rendering del server

Le persone hanno eseguito correttamente il rendering sul server con Flux, ma visto che abbiamo 20 librerie Flux ognuna delle quali tenta di rendere il rendering del server "più semplice", forse Flux ha dei bordi irregolari sul server. La verità è che Facebook non esegue molto il rendering dei server, quindi non ne sono stati molto preoccupati e si basano sull'ecosistema per renderlo più semplice.

Nel Flux tradizionale, i negozi sono singoli. Ciò significa che è difficile separare i dati per diverse richieste sul server. Non impossibile, ma difficile. Questo è il motivo per cui la maggior parte delle librerie Flux (così come le nuove Utilità Flux ) ora suggeriscono di utilizzare le classi anziché i singoli, in modo da poter creare istanze di negozi per richiesta.

Ci sono ancora i seguenti problemi che devi risolvere in Flux (da solo o con l'aiuto della tua libreria Flux preferita come Flummox o Alt ):

  • Se i negozi sono classi, come posso crearli e distruggerli con il dispatcher per richiesta? Quando registro i negozi?
  • Come posso idratare i dati dai negozi e successivamente reidratarli sul client? Devo implementare metodi speciali per questo?

Devo ammettere che i framework Flux (non Vanilla Flux) hanno soluzioni a questi problemi, ma li trovo troppo complicati. Ad esempio, Flummox ti chiede di implementare serialize()e deserialize()nei tuoi negozi . Alt risolve questo problema fornendo takeSnapshot()che serializza automaticamente il tuo stato in un albero JSON.

Redux va oltre: poiché esiste un solo negozio (gestito da molti riduttori), non è necessaria alcuna API speciale per gestire la (ri) idratazione. Non è necessario "svuotare" o "idratare" i negozi: esiste un solo negozio e puoi leggere il suo stato corrente o creare un nuovo negozio con un nuovo stato. Ogni richiesta ottiene un'istanza del negozio separata. Ulteriori informazioni sul rendering del server con Redux.

Ancora una volta, questo è un caso di qualcosa di possibile sia in Flux che in Redux, ma le librerie Flux risolvono questo problema introducendo una tonnellata di API e convenzioni e Redux non deve nemmeno risolverlo perché non ha quel problema nel primo posto grazie alla semplicità concettuale.

Esperienza degli sviluppatori

In realtà non volevo che Redux diventasse una popolare libreria Flux: l'ho scritto mentre stavo lavorando al mio discorso su ReactEurope sul caldo ricaricare con i viaggi nel tempo . Avevo un obiettivo principale: rendere possibile cambiare al volo il codice del riduttore o addirittura "cambiare il passato" barrando le azioni e vedere lo stato ricalcolato.

Non ho visto una singola libreria Flux in grado di farlo. React Hot Loader inoltre non ti consente di farlo, infatti si rompe se modifichi i negozi Flux perché non sa cosa farne.

Quando Redux deve ricaricare il codice del riduttore, chiama replaceReducer()e l'app viene eseguita con il nuovo codice. In Flux, i dati e le funzioni sono intrecciati nei negozi Flux, quindi non è possibile "semplicemente sostituire le funzioni". Inoltre, dovresti in qualche modo registrare nuovamente le nuove versioni con Dispatcher, cosa che Redux non ha nemmeno.

Ecosistema

Redux ha un ecosistema ricco e in rapida crescita . Questo perché fornisce alcuni punti di estensione come il middleware . È stato progettato tenendo conto di casi d'uso come registrazione , supporto per promesse , osservabili , routing , controlli di sviluppo dell'immutabilità , persistenza , ecc. Non tutti si riveleranno utili, ma è bello avere accesso a una serie di strumenti che possono essere facilmente combinati per lavorare insieme.

Semplicità

Redux conserva tutti i vantaggi di Flux (registrazione e riproduzione di azioni, flusso di dati unidirezionale, mutazioni dipendenti) e aggiunge nuovi vantaggi (annullamento della ripetizione, ricarica a caldo) senza introdurre Dispatcher e la registrazione del negozio.

Mantenerlo semplice è importante perché ti mantiene sano mentre implementi le astrazioni di livello superiore.

A differenza della maggior parte delle librerie Flux, la superficie dell'API Redux è minuscola. Se rimuovi gli avvisi, i commenti e i controlli di integrità dello sviluppatore, sono 99 righe . Non esiste un codice asincrono complicato per il debug.

Puoi effettivamente leggerlo e capire tutto di Redux.


Vedi anche la mia risposta agli aspetti negativi dell'utilizzo di Redux rispetto a Flux .


3
grazie per la risposta ... Sono nuovo di js.. nella tua risposta hai detto che il flusso sta usando il modello di progettazione singleton ... puoi dirmi in redux che tipo di modello di design stanno usando ... e nel flusso puoi mi dici dove stanno usando il modello singleton ... puoi dare entrambi un esempio ... ho capito cosa significa il modello di progettazione da qui singleton

2
Ho iniziato la mia implementazione Android / Java (Fluxxan) basata su Fluxxor (fondamentalmente flusso puro). Una volta che ho visto redux, sono stato venduto. Ci sono alcune porzioni che ho mantenuto puramente flusso, ma amico, la tua lib è fantastica!
gelido

5
Vuoi imparare Redux? guarda questo video: youtube.com/watch?v=ucd5x3Ka3gw
gsalgadotoledo

5
Abbiamo scelto il redux perché è molto più supponente del flusso. Abbiamo costantemente litigato su come / dove dovrebbe andare un determinato codice, ecc. Redux ha rimosso tutta quella confusione per noi. Abbiamo creato app con redux per il web e la reattività nativa ed è incredibile !!
Qualcosa il

1
La linea github.com/reactjs/redux/blob/… è stata la risposta alla domanda che cercavo da una settimana: come strutturare il negozio e i riduttori, in modo che più istanze di componenti riutilizzabili utilizzate in contesti diversi possano essere gestite senza duplicare logica. La risposta sembra essere: utilizzare tre livelli deep store: 1 ° livello: nome del componente ("impaginazione"), 2 ° livello: nome del contenitore ("stargazersByRepo"), 3 livello: la chiave / ID univoci del contenitore ( ${login}/${name}). Grazie mille!
qbolec,

101

A Quora qualcuno dice :

Prima di tutto, è assolutamente possibile scrivere app con React senza Flux.

Anche questo diagramma visivo che ho creato per mostrare una rapida visione di entrambi, probabilmente una risposta rapida per le persone che non vogliono leggere l'intera spiegazione: Flux vs Redux

Ma se sei ancora interessato a saperne di più, continua a leggere.

Credo che dovresti iniziare con React puro, quindi imparare Redux e Flux. Dopo aver fatto un'esperienza REALE con React, vedrai se Redux ti sarà utile o meno.

Forse sentirai che Redux è esattamente per la tua app e forse scoprirai che Redux sta cercando di risolvere un problema che non riscontri davvero.

Se inizi direttamente con Redux, potresti finire con codice troppo ingegnerizzato, codice più difficile da mantenere e con ancora più bug e che senza Redux.

Dai documenti Redux :

Motivazione
Poiché i requisiti per le applicazioni JavaScript a pagina singola sono diventati sempre più complicati, il nostro codice deve gestire più stato che mai. Questo stato può includere le risposte del server e i dati memorizzati nella cache, nonché i dati creati localmente che non sono stati ancora persistiti sul server. Anche lo stato dell'interfaccia utente sta aumentando in complessità, poiché è necessario gestire percorsi attivi, schede selezionate, spinner, controlli di impaginazione e così via.

Gestire questo stato in continua evoluzione è difficile. Se un modello può aggiornare un altro modello, una vista può aggiornare un modello, che aggiorna un altro modello e questo, a sua volta, potrebbe causare l'aggiornamento di un'altra vista. Ad un certo punto, non capisci più cosa succede nella tua app poiché hai perso il controllo su quando, perché e come del suo stato. Quando un sistema è opaco e non deterministico, è difficile riprodurre bug o aggiungere nuove funzionalità.

Come se ciò non bastasse, considera i nuovi requisiti diventare comuni nello sviluppo del prodotto front-end. Come sviluppatori, ci si aspetta che gestiamo gli aggiornamenti ottimistici, il rendering sul lato server, il recupero dei dati prima di eseguire le transizioni di route e così via. Ci troviamo a cercare di gestire una complessità che non abbiamo mai avuto a che fare prima e inevitabilmente ci poniamo la domanda: è tempo di arrendersi? La risposta è no.

Questa complessità è difficile da gestire poiché stiamo mescolando due concetti che sono molto difficili da ragionare per la mente umana: mutazione e asincronicità. Li chiamo Mentos e Coca-Cola. Entrambi possono essere fantastici quando separati, ma insieme creano un casino. Le librerie come React tentano di risolvere questo problema nel livello di visualizzazione rimuovendo sia la sincronizzazione asincrona che la manipolazione DOM diretta. Tuttavia, la gestione dello stato dei dati è lasciata a te. È qui che entra in gioco Redux.

Seguendo le orme di Flux, CQRS ed Event Sourcing, Redux tenta di rendere prevedibili le mutazioni di stato imponendo alcune restrizioni su come e quando possono avvenire gli aggiornamenti. Queste restrizioni si riflettono nei tre principi di Redux.

Anche dai documenti Redux :

Concetti fondamentali Lo
stesso Redux è molto semplice.

Immagina che lo stato della tua app sia descritto come un semplice oggetto. Ad esempio, lo stato di un'app todo potrebbe essere simile al seguente:

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

Questo oggetto è come un "modello", tranne per il fatto che non ci sono setter. Questo è così che diverse parti del codice non possono cambiare lo stato in modo arbitrario, causando bug difficili da riprodurre.

Per cambiare qualcosa nello stato, devi inviare un'azione. Un'azione è un semplice oggetto JavaScript (noti come non introduciamo alcuna magia?) Che descrive cosa è successo. Ecco alcuni esempi di azioni:

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

Applicare che ogni modifica sia descritta come un'azione ci consente di avere una chiara comprensione di ciò che sta accadendo nell'app. Se qualcosa è cambiato, sappiamo perché è cambiato. Le azioni sono come il pangrattato di ciò che è accaduto. Infine, per legare insieme stato e azioni, scriviamo una funzione chiamata riduttore. Ancora una volta, niente di magico al riguardo: è solo una funzione che prende stato e azione come argomenti e restituisce il prossimo stato dell'app. Sarebbe difficile scrivere una tale funzione per una grande app, quindi scriviamo funzioni più piccole che gestiscono parti dello stato:

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter;
  } else {
    return state;
  }
}

function todos(state = [], action) {
  switch (action.type) {
  case 'ADD_TODO':
    return state.concat([{ text: action.text, completed: false }]);
  case 'TOGGLE_TODO':
    return state.map((todo, index) =>
      action.index === index ?
        { text: todo.text, completed: !todo.completed } :
        todo
   )
  default:
    return state;
  }
}

E scriviamo un altro riduttore che gestisce lo stato completo della nostra app chiamando quei due riduttori per le corrispondenti chiavi di stato:

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  };
}

Questa è sostanzialmente l'idea di Redux. Tieni presente che non abbiamo utilizzato API Redux. Viene fornito con alcune utility per facilitare questo modello, ma l'idea principale è che descrivi come il tuo stato viene aggiornato nel tempo in risposta a oggetti di azione, e il 90% del codice che scrivi è semplicemente JavaScript, senza usare Redux stesso, le sue API o qualsiasi magia.


57

Potrebbe essere meglio iniziare con la lettura di questo post di Dan Abramov in cui discute varie implementazioni di Flux e dei loro compromessi nel momento in cui stava scrivendo redux: The Evolution of Flux Frameworks

In secondo luogo, la pagina delle motivazioni a cui ci si collega non discute in realtà le motivazioni di Redux tanto quanto le motivazioni alla base di Flux (e React). I tre principi è più specifico di Redux, sebbene non affronti ancora le differenze di implementazione rispetto all'architettura Flux standard.

Fondamentalmente, Flux ha più negozi che calcolano il cambio di stato in risposta alle interazioni UI / API con i componenti e trasmettono queste modifiche come eventi a cui i componenti possono abbonarsi. In Redux, esiste un solo negozio a cui ogni componente si abbona. IMO sembra almeno che Redux semplifichi e unifichi ulteriormente il flusso di dati unificando (o riducendo, come direbbe Redux) il flusso di dati ai componenti, mentre Flux si concentra sull'unificazione dell'altro lato del flusso di dati. modello.


27

Sono uno dei primi utilizzatori e ho implementato un'applicazione di una sola pagina di medie dimensioni utilizzando la libreria Facebook Flux.

Dato che sono un po 'in ritardo nella conversazione, sottolineo solo che, nonostante le mie migliori speranze, Facebook sembra considerare la loro implementazione Flux come una prova del concetto e non ha mai ricevuto l'attenzione che merita.

Ti incoraggio a giocarci, in quanto espone maggiormente il funzionamento interno dell'architettura Flux che è piuttosto educativo, ma allo stesso tempo non offre molti dei vantaggi che forniscono le biblioteche come Redux (che non lo sono quello importante per i piccoli progetti, ma diventa molto prezioso per quelli più grandi).

Abbiamo deciso che andando avanti ci trasferiremo a Redux e ti suggerisco di fare lo stesso;)


Sto sviluppando l'app Facebook Flux da sei mesi. E non sono ancora sicuro se un tempo di migrazione valga i vantaggi offerti da Redux. Apprezzerò molto tutti i tuoi commenti sui pro / contro di Redux sul flusso FB!
VB_11

1
@VolodymyrBakhmatiuk per noi riguarda principalmente la riduzione della quantità di boilerplate che dobbiamo scrivere + una migliore gestione degli errori (il redux ad esempio urlerà se spari un'azione che non è stata definita nell'elenco costante - il flusso di FB non lo farà e può causare tutto tipi di problemi) Ci sono alcune funzionalità più avanzate nel flusso, ma non le ho ancora utilizzate
Guy Nesher,

1
@GuyNesher un'azione non definita deve essere rilevata in fase di compilazione, non in fase di esecuzione. Flow (un altro contributo di Facebook) ti consente di farlo.
Dominique PERETTI,

@DominiquePERETTI - vero (può anche usare la lanugine) ma non cambia il fatto che non rilevare l'errore in fase di esecuzione è un po 'triste
Guy Nesher,

Ho scritto alcuni semplici aiutanti per gestire FBFlux, e in realtà sembra che siano meno piatti e impostazioni delle app rispetto a tutte le app Redux di esempio che ho trovato. Ho lavorato su un'app per più di 9 mesi tra due sviluppatori e non ho mai avuto problemi di architettura.
rob2d

20

Ecco la semplice spiegazione di Redux su Flux. Redux non ha un dispatcher, ma si basa su funzioni pure chiamate riduttori. Non ha bisogno di un dispatcher. Ogni azione è gestita da uno o più riduttori per aggiornare il singolo negozio. Poiché i dati sono immutabili, i riduttori restituiscono un nuovo stato aggiornato che aggiorna il negozioinserisci qui la descrizione dell'immagine

Per ulteriori informazioni Flux vs Redux


A proposito di più negozi, ora è qualcosa di fattibile in Redux, in reatt-redux è possibile aggiungere una chiave per isolare i negozi: campione di lavoro redux.js.org/faq/storesetup : github.com/Lemoncode/redux-multiple-stores
Braulio

6

Ho lavorato parecchio tempo con Flux e ora parecchio tempo con Redux. Come ha sottolineato Dan, entrambe le architetture non sono così diverse. Il fatto è che Redux rende le cose più semplici e pulite. Ti insegna un paio di cose su Flux. Come ad esempio Flux è un perfetto esempio di flusso di dati a una direzione. Separazione delle preoccupazioni in cui sono presenti dati, manipolazioni e livelli di visualizzazione separati. In Redux abbiamo le stesse cose ma impariamo anche l'immutabilità e le funzioni pure.


5

Da un nuovo adozione di reagenti / redux che migra da (alcuni anni di) ExtJS a metà 2018:

Dopo aver fatto scorrere indietro la curva di apprendimento del redux, ho avuto la stessa domanda e ho pensato che il flusso puro sarebbe stato più semplice come OP.

Presto vidi i vantaggi del flusso rosso rispetto al flusso, come indicato nelle risposte sopra, e lo stavo lavorando nella mia prima app.

Mentre mi afferravo di nuovo sulla piastra della caldaia, ho provato alcune delle altre librerie di gestione dello stato, la migliore che ho trovato è stata la rivincita .

Era molto più intuitivo del redux alla vaniglia, tagliava il 90% della piastra della caldaia e tagliava il 75% del tempo che stavo spendendo per il redux (cosa che penso dovrebbe fare una libreria), sono stato in grado di ottenere un paio di app aziendali andando subito.

Funziona anche con gli stessi strumenti di redux. Questo è un buon articolo che copre alcuni dei vantaggi.

Quindi, per chiunque sia arrivato a questo post SO alla ricerca di "redux più semplice", consiglio di provarlo come una semplice alternativa al redux con tutti i vantaggi e 1/4 della piastra della caldaia.


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.