Warum Redux-Observable über Redux-Saga verwenden?

133

Ich habe Redux-Saga verwendet . Der damit geschriebene Code ist bisher leicht zu begründen, außer dass die JS-Generatorfunktion von Zeit zu Zeit meinen Kopf durcheinander bringt. Nach meinem Verständnis kann Redux-Observable einen ähnlichen Job ausführen , der Nebenwirkungen behandelt, jedoch ohne Verwendung der Generatorfunktion.

Dokumente von Redux-Observable liefern jedoch nicht viele Meinungen darüber, warum es Redux-Saga überlegen ist. Ich würde gerne wissen, ob die Verwendung der Generatorfunktion der einzige Vorteil der Verwendung von Redux-Observable ist. Und was könnten die Nachteile, Probleme oder Kompromisse bei der Verwendung von Redux-Observable anstelle von Redux-Saga sein? Danke im Voraus.

Ivan Wang
quelle
Ich hatte einen lustigen, aber detaillierten Blog gemacht, in dem ich Redux-Saga als Redux-Observable überlegen fand, für Leute, die nicht den ganzen Tag Observables leben / essen / atmen. Ich bin sicher, es ist großartig, wenn Ihr ganzer Stapel beobachtbar ist. shift.infinite.red/…
Gant Laborde

Antworten:

236

Haftungsausschluss: Ich bin einer der Autoren von Redux-Observable, daher fällt es mir schwer, 100% unparteiisch zu sein.

Wir geben derzeit keinen Grund an, warum Redux-Observable besser ist als Redux-Saga, weil ... es nicht ist. 😆

Es gibt Vor- und Nachteile für beide. Viele werden feststellen, dass einer intuitiver ist als der andere, aber beide sind auf unterschiedliche Weise komplex zu lernen, wenn Sie RxJS (redux-beobachtbar) oder Generatoren / "Effekte als Daten" (Redux-Saga) nicht kennen.

Sie lösen das gleiche Problem auf äußerst ähnliche Weise, weisen jedoch einige grundlegende Unterschiede auf, die erst dann wirklich sichtbar werden, wenn Sie sie ausreichend verwenden.

Redux-Observable verschiebt fast alles auf idiomatisches RxJS. Wenn Sie also über RxJS-Kenntnisse verfügen (oder diese erwerben), ist das Lernen und Verwenden von Redux-Observable super super natürlich. Das bedeutet auch, dass dieses Wissen auf andere Dinge als Redux übertragbar ist. Wenn Sie sich für einen Wechsel zu MobX entscheiden, wenn Sie sich für einen Wechsel zu Angular2 entscheiden, wenn Sie sich für einen Wechsel zu einer zukünftigen Hotness X entscheiden, stehen die Chancen sehr gut, dass RxJS Ihnen helfen kann. Dies liegt daran, dass RxJS eine generische asynchrone Bibliothek ist und in vielerlei Hinsicht wie eine Programmiersprache an sich ist - das gesamte Paradigma der "reaktiven Programmierung". RxJS existiert seit 2012 und wurde als Port von Rx.NET gestartet (es gibt "Ports" in fast jeder wichtigen Sprache, es ist so nützlich ).

redux-saga stellt seine zeitbasierten Operatoren selbst zur Verfügung. Während das Wissen, das Sie über Generatoren und den Umgang mit Nebenwirkungen in diesem Prozessmanager-Stil erwerben, übertragbar ist, werden die tatsächlichen Operatoren und die Verwendung in keiner anderen wichtigen Bibliothek verwendet. Das ist ein bisschen unglücklich, sollte aber auf keinen Fall ein Deal-Breaker für sich sein.

Es werden auch "Effekte als Daten" ( hier beschrieben ) verwendet, was zunächst schwierig sein kann, aber es bedeutet, dass Ihr Redux-Saga-Code die Nebenwirkungen selbst nicht ausführt. Stattdessen erstellen die von Ihnen verwendeten Hilfsfunktionen Objekte, die Aufgaben ähneln, die die Absicht darstellen, den Nebeneffekt auszuführen, und die die interne Bibliothek dann für Sie ausführt. Dies macht das Testen extrem einfach, ohne dass man sich verspotten muss, und ist für manche Menschen sehr attraktiv. Ich persönlich habe jedoch festgestellt, dass Ihre Unit-Tests einen Großteil der Logik Ihrer Saga neu implementieren - was diese Tests IMO nicht sehr nützlich macht (diese Meinung wird nicht von allen geteilt).

Die Leute fragen oft, warum wir so etwas nicht mit Redux-Observable machen: Für mich ist es grundsätzlich nicht kompatibel mit normalem idiomatischem Rx. In Rx verwenden wir .debounceTime()solche Operatoren , die die zum Entprellen erforderliche Logik kapseln. Wenn wir jedoch eine Version davon erstellen möchten, die das Entprellen nicht tatsächlich durchführt und stattdessen Aufgabenobjekte mit der Absicht ausgibt, haben Sie jetzt die verloren Leistung von Rx, weil Sie nicht mehr nur Operatoren verketten können, weil sie an diesem Task-Objekt arbeiten würden, nicht das eigentliche Ergebnis der Operation. Das ist wirklich schwer elegant zu erklären. Es erfordert wiederum ein umfassendes Verständnis von Rx, um die Inkompatibilität von Ansätzen zu verstehen. Wenn Sie so etwas wirklich wollen, schauen Sie sich das an Redux-Zyklen andie cycle.js verwendet und meistens diese Ziele hat. Ich finde, es erfordert zu viel Zeremonie für meinen Geschmack, aber ich ermutige Sie, es zu versuchen, wenn es Sie interessiert.

Wie ThorbenA erwähnte, scheue ich mich nicht zuzugeben, dass die Redux-Saga derzeit (13.10.16) der klare Marktführer im komplexen Management von Nebenwirkungen für Redux ist. Es wurde früher gestartet und hat eine robustere Community. Es ist also sehr attraktiv, den De-facto-Standard gegenüber dem neuen Kind auf dem Block anzuwenden. Ich denke, es ist sicher zu sagen, wenn Sie beides ohne Vorkenntnisse verwenden, werden Sie verwirrt sein. Wir verwenden beide ziemlich fortschrittliche Konzepte, die das komplexe Management von Nebenwirkungen erheblich vereinfachen, sobald Sie es "bekommen", aber bis dahin stolpern viele.

Der wichtigste Rat, den ich geben kann, ist, keine dieser Bibliotheken einzubringen, bevor Sie sie benötigen. Wenn Sie nur einfache Ajax-Anrufe tätigen, brauchen Sie diese wahrscheinlich nicht. Redux-Thunk ist dumm, einfach zu erlernen und bietet genug für die Grundlagen - aber je komplexer die Asynchronität, desto schwieriger (oder sogar unmöglich) wird es für Redux-Thunk. Aber für Redux-Observable / Saga scheint es in vielerlei Hinsicht am komplexesten, je komplexer die Asynchronität ist. Es ist auch eine Menge Verdienst, Redux-Thunk mit einem der anderen (Redux-Observable / Saga) im selben Projekt zu verwenden! Redux-Thunk für Ihre üblichen einfachen Sachen und dann nur Redux-Observable / Saga für komplexe Sachen. Das ist eine großartige Möglichkeit, um produktiv zu bleiben. Sie kämpfen also nicht gegen Redux-Observable / Saga um Dinge, die mit Redux-Thunk trivial wären.

Jayphelps
quelle
3
Habe gerade dein Gespräch gesehen (uuhf der Ton!) Und sofort ⌘ + T + "Redux-Saga vs Redux-Observable" gedrückt. Ich benutze Redux-Saga schon seit einiger Zeit (besonders in React Native), aber nachdem ich Ihren Vortrag und diesen Beitrag gesehen habe, kann ich einige Anwendungsfälle (für mich) sehen, in denen Redux-obs. wäre eigentlich eine bessere Passform. Ihr Beispiel, debounceTime()dass Sie die Kontrolle über eine sehr generische Logik "verloren" haben, hat es für mich getroffen. Danke für die Erklärung.
Hulvej
3
Ich habe gerade das Gespräch gesehen und ein bisschen mehr gegoogelt. Gutes Zeug @jayphelps, danke fürs Teilen. Ich mag besonders Ihren Kommentar zur Verwendung von Redux-Thunk in Verbindung mit Redux-Observable / Saga. Das macht sehr viel Sinn, warum einfache AJAX-Anfragen zu kompliziert werden, wenn dies nicht erforderlich ist. Das heißt, es gibt etwas zu sagen für Einheitlichkeit und Konsistenz der Menschen. Danke noch einmal!
Spets
Vor dem Upgrade auf Redux-Saga / Redux-Observable können Sie Redux-Dispatch-Listener ausprobieren. Dies ist sehr einfach und kann bereits einige Ihrer Anwendungsfälle lösen: github.com/slorber/redux-dispatch-subscribe
Sebastien Lorber
Dies war eine sehr nützliche Antwort. Danke dir! Ich mag den Punkt, Wissen über RxJS auf andere Domänen / Frameworks übertragen zu können.
Anselan
@ Jayphelps Was wäre ein Beispiel für "komplexe Asynchronität". Ich versuche gerade zu beurteilen, ob ich für ein Projekt von Thunk zu Saga / Observables wechseln soll. Danke :)
Sam Bokai
64

Ich denke, es gibt Dinge, die Sie berücksichtigen müssen.

  1. Komplexität
  2. Codierungsstil
  3. Lernkurve
  4. Testbarkeit

Nehmen wir an, wir möchten Benutzer von der API abrufen

// Redux-Saga

import axios from 'axios' 

function* watchSaga(){
  yield takeEvery('fetch_user', fetchUser) // waiting for action (fetch_user)
}

function* fetchUser(action){
    try {
        yield put({type:'fetch_user_ing'})
        const response = yield call(axios.get,'/api/users/1')
        yield put({type:'fetch_user_done',user:response.data})
  } catch (error) {
        yield put({type:'fetch_user_error',error})
  }
}

// Redux-Observable
import axios from 'axios'

const fetchUserEpic = action$ => 
    action$
        .ofType('fetch_user')
        .flatMap(()=>
          Observable.from(axios.get('/api/users/1')) // or use Observable.ajax
            .map(response=>({type:'fetch_user_done', user:response.data}))
            .catch(error => Observable.of({type:'fetch_user_error',error}))
            .startWith({type:'fetch_user_ing'})
        )

Außerdem habe ich diesen Artikel geschrieben, um die Unterschiede zwischen Redux-Saga und Redux-Observable in der Tiefe zu vergleichen. Schauen Sie sich diesen Link hier oder die Präsentation an .

Wayne Chiu
quelle
3
Dieser Side-by-Side-Vergleich von dem Link ist großartig, danke
Rofrol
1
Ich liebe den Vergleich, ABER es gibt ein Problem damit, das ich ansprechen möchte. Wenn Sie sie mit API-Aufrufen vergleichen, verwenden Sie Fetch für Redux-Observable. cool. ABER wenn Sie "stornierbare" Unterschiede zeigen, verwenden Sie NICHT fetch - stattdessen verwenden Sie die interne Observable.ajax ... warum? Ich würde es vorziehen, es mit "fetch" oder "axios" zu behalten. Ansonsten tolle Arbeit dort.
James Emanon
5
@jamesemanon Ich gehe davon aus, dass er Fetch nicht verwendet, da die Fetch-API noch keine Option zum Abbrechen hat. (mehr dazu: github.com/whatwg/fetch/issues/27 )
Daniel Andrei
Wow, dieser eingehende Vergleich mit allen Beispielen ist der beste. Danke dir!
Radek Matěj
22

Ich verwende Redux-Observable gegenüber Redux-Saga, weil ich lieber mit Observables als mit Generatoren arbeite. Ich benutze es mit RXJS, einer leistungsstarken Bibliothek für die Arbeit mit Datenströmen. Betrachten Sie es als Lodash für Async. Schauen Sie sich diese Antwort von Jay Phelps an , um Nachteile, Probleme und Kompromisse bei der Auswahl zu erkennen :

Redux-Saga als Projekt existiert schon länger als Redux-beobachtbar, das ist sicherlich ein wichtiges Verkaufsargument. Sie finden mehr Dokumentation, Beispiele und wahrscheinlich eine bessere Community, von der Sie Unterstützung erhalten können.

Der Zähler ist, dass die Operatoren und APIs, die Sie in der Redux-Saga lernen, bei weitem nicht so übertragbar sind wie das Lernen von RxJS, das überall verwendet wird. redux-beobachtbar ist intern super super super einfach, es gibt Ihnen wirklich nur eine natürliche Möglichkeit, RxJS zu verwenden. Wenn Sie also RxJS kennen (oder wollen), ist dies eine äußerst natürliche Passform.

Mein momentaner Rat für die meisten Menschen ist, dass Sie sich wahrscheinlich für die Redux-Saga entscheiden sollten, wenn Sie sich fragen müssen, welche Sie verwenden sollten.

ThorbenA
quelle
9

Redux-Observable ist eine erstaunliche Bibliothek. Wir verwenden sie 1,5 Jahre lang ohne Probleme in der Produktion. Sie ist perfekt testbar und kann problemlos in jedes Framework integriert werden. Wir haben extrem überlastete parallele Socket-Kanäle und das einzige, was uns vor dem Einfrieren bewahrt, ist Redux-Observable

Ich habe 3 Punkte, die ich hier erwähnen möchte.

1. Komplexität und Lernkurve

Redux-Saga schlägt hier leicht Redux-beobachtbar. Wenn Sie nur eine einfache Anfrage benötigen, um die Autorisierung durchzuführen, und aus bestimmten Gründen kein Redux-Thunk verwenden möchten, sollten Sie die Verwendung der Redux-Saga in Betracht ziehen. Dies ist nur einfacher zu verstehen.

Wenn Sie keine Vorkenntnisse in Observable haben, wird es Ihnen weh tun und Ihr Team wird Sie auf Kurs bringen :)

2. Was können Observable und RxJS mir bieten?

Wenn es um asynchrone Logik geht, ist Observable Ihr Schweizer Messer. Observable kann buchstäblich fast alles für Sie tun. Sie sollten sie niemals mit Versprechungen oder Generatoren vergleichen, sie sind weitaus leistungsfähiger als der Vergleich von Optimus Prime mit Chevrolet.

Und was ist mit RxJS? Es ist wie lodash.js, aber für asynchrone Logik, wenn Sie einmal drin sind, werden Sie nie mehr zu etwas anderem wechseln.

3. Reaktive Erweiterung

Überprüfen Sie einfach diesen Link

http://reactivex.io/languages.html

Die reaktive Erweiterung ist für alle modernen Programmiersprachen implementiert und nur Ihr Schlüssel zur funktionalen Programmierung.

Verbringen Sie also Ihre Zeit mit Bedacht, lernen Sie RxJS und verwenden Sie Redux-Observable :)

Denis Rybalka
quelle
7

Ich schätze die Übertragbarkeit zwischen Sprachen und Laufzeiten, die Rx hat. Auch wenn Ihre App die Sprache nicht ändert, kann Ihre Karriere. Holen Sie sich den bestmöglichen Hebel für Ihr Lernen, wie auch immer Sie es selbst einschätzen. Es ist ein großartiges Tor zu .Net LINQ.

Dean Radcliffe
quelle
2
Kluge Wahl, obwohl Generatoren auch sprachunabhängig sind.
Greg Herbowicz
3

Da es hier eine ganze Reihe von Redux-beobachtbaren Gesprächen gibt, hatte ich gedacht, ich würde die Saga-Seite des Arguments angeben. Ich verwende kein Redux-Observable oder RxJS, daher kann ich keinen Vergleich nebeneinander geben, aber ich habe Sagen mit großer Wirkung verwendet.

Für was es wert ist, verwende ich Sagen in der Produktion in einer Webanwendung.

Sagas gegen Thunk

Saga gewinnt zweifellos. Ich mochte es nicht, wie Thunk meinen Action-Machern Logik verlieh. Es machte es auch schwierig, einige Anfragen hintereinander zu erledigen. Ich habe mir kurz Redux-Observable für diesen Job angesehen, mich aber für Sagas entschieden.

Lernkurve für Sagas

Zu verstehen, was Generatoren sind und warum sie wichtig sind, ist der Schlüssel zum Verständnis von Sagen. Aber ich will betonen , dass Sie nicht brauchen , Generatoren zu wissen innen und außen. Sie müssen nur wissen, dass Sie die Kontrolle mit der Yield-Anweisung abgeben und dass die Saga die Kontrolle zurückgibt, nachdem Ihr asynchroner Code aufgelöst wurde. Nach diesem Moment ist es nicht sehr schwer zu verstehen, was in einer Saga vor sich geht.

Die Kernmethoden der Saga sind (meiner Erfahrung nach):

  • call- Rufen Sie einen beliebigen Code auf und erhalten Sie den Rückgabewert. Unterstützt Versprechen. Große Synergie zwischen asynchroner Verarbeitung und Sagen.
  • select- Rufen Sie einen Selektor. Dieses Stück ist ziemlich brillant. Selektoren sind der Kern von Redux und werden zu 100% unterstützt!
  • put- aka dispatcheine Aktion. Versenden Sie tatsächlich so viele, wie Sie möchten!

Es gibt andere Funktionen, aber wenn Sie diese drei beherrschen, sind Sie an einem wirklich guten Ort.

Fazit

Der Grund, warum ich mich für Sagen entschieden habe, war die Benutzerfreundlichkeit. Redux-Observable sah nach einer Herausforderung aus. Ich bin 100% zufrieden mit Sagen. Glücklicher als ich jemals erwartet hatte.

Nach meiner Erfahrung sind Sagas (viel) besser als Thunks und relativ leicht zu verstehen. Rx ist nicht jedermanns Sache. Ich würde Sagas nachdrücklich in Betracht ziehen, anstatt Redux zu beobachten, wenn Sie nicht aus diesem Ökosystem stammen und / oder nicht vorhaben, Rx in Zukunft zu verwenden.

Julius Ecker
quelle
2

Wenn Sie Ihre Anwendung in Typescript schreiben, empfehle ich, typlos zu überprüfen . Es ist von Redux-Observable inspiriert und hängt auch von RxJS ab, aber es gibt das gesamte Ökosystem für die Erstellung der App.

Die größten Nachteile von Redux-Observable / Redux-Saga sind fehlende Richtlinien. Es gibt keine offiziellen Richtlinien, wie man Lastreduzierer, Sagen oder Epen faul macht. Die Code-Aufteilung ist beim Skalieren größerer Apps von entscheidender Bedeutung. Benutzerdefinierte Lösungen für das verzögerte Laden funktionieren normalerweise nicht mit HMR, was zu einer schlechten Entwicklererfahrung führt.

Typlose Profis:

  1. Entwickelt für TypeScript
    Alle APIs sind für Typoskript und Typensicherheit konzipiert:
    • Typoskript steigert Ihre Produktivität und verlangsamt Sie nicht.
    • Es sind nur die erforderlichen Anmerkungen erforderlich: Status, Aktionsargumente.
    • Keine Typografie. Alles wird automatisch abgeleitet. 95% des Codes sehen aus wie reines Javascript.
    • Keine RootAction-, RootEpic-, RootState- oder andere Hilfstypen.
  2. Stellen Sie alle Bausteine ​​bereit
    • Typeless enthält alles, um mittelgroße Apps oder Apps auf Unternehmensebene zu erstellen.
    • Sie müssen sich nicht auf mehrere kleine Bibliotheken verlassen.
  3. Modularität
    • Die richtige Modularität ist entscheidend für die Erstellung skalierbarer Apps.
    • Es ist nicht erforderlich, Root-Dateien für Epen, Reduzierungen, Typen usw. zu erstellen. Sobald Sie ein neues Modul erstellt haben, können Sie es von jedem Ort aus anhängen. Ähnlich wie bei Standard-React-Komponenten.
  4. Rechthaberisch
    • Alle gängigen Anwendungsfälle und Probleme werden standardmäßig gelöst. Sie müssen nicht überlegen, wie Sie triviale Probleme beheben können.
    • Alle Empfehlungen und Best Practices werden bereitgestellt!

Überprüfen Sie https://typeless.js.org/

Himmel
quelle
1
Sie sollten einen Haftungsausschluss hinzufügen, wenn Sie Software empfehlen, für die Sie der Hauptverantwortliche sind.
Hagelt18