Pourquoi utiliser Redux-Observable sur Redux-Saga?

133

J'ai utilisé Redux-Saga . Le code écrit avec est facile à raisonner jusqu'à présent, sauf que la fonction de générateur JS me dérange de temps en temps. D'après ce que je comprends, Redux-Observable peut réaliser le travail similaire qui gère les effets secondaires mais sans utiliser la fonction de générateur.

Cependant, les documents de Redux-Observable ne fournissent pas beaucoup d'opinions sur les raisons pour lesquelles il est supérieur à Redux-Saga. Je voudrais savoir si le fait de ne pas utiliser la fonction de générateur est le seul avantage de l'utilisation de Redux-Observable. Et quels pourraient être les inconvénients, les pièges ou les compromis liés à l'utilisation de Redux-Observable au lieu de Redux-Saga? Merci d'avance.

Ivan Wang
la source
J'avais fait un blog amusant mais détaillé où j'ai trouvé Redux-Saga supérieur à Redux-Observable pour les personnes qui ne vivent pas / mangent / respirent les observables toute la journée. Je suis sûr que c'est génial si toute votre pile est observable. shift.infinite.red
Gant Laborde

Réponses:

236

Avertissement: je suis l'un des auteurs de redux-observable, il m'est donc difficile d'être à 100% impartial.

Nous ne fournissons actuellement aucune raison pour laquelle redux-observable est meilleur que redux-saga parce que ... ce n'est pas le cas. 😆

tl; dr il y a des avantages et des inconvénients aux deux. Beaucoup trouveront l'un plus intuitif que l'autre, mais les deux sont complexes à apprendre de différentes manières si vous ne connaissez pas RxJS (redux-observable) ou générateurs / "effets sous forme de données" (redux-saga).

Ils résolvent le même problème de manière extrêmement similaire, mais présentent des différences fondamentales qui ne deviennent vraiment apparentes qu'une fois que vous les utilisez suffisamment.

redux-observable reporte presque tout à RxJS idiomatique. Donc, si vous avez des connaissances RxJS (ou les acquérez), apprendre et utiliser redux-observable est super naturel. Cela signifie également que cette connaissance est transférable à des choses autres que redux. Si vous décidez de passer à MobX, si vous décidez de passer à Angular2, si vous décidez de passer à une future hotness X, il y a de fortes chances que RxJS puisse vous aider. C'est parce que RxJS est une bibliothèque asynchrone générique, et à bien des égards ressemble à un langage de programmation en lui-même - le paradigme de la «programmation réactive». RxJS existe depuis 2012 et a commencé comme un port de Rx.NET (il y a des «ports» dans presque toutes les langues principales, c'est aussi utile ).

redux-saga fournit lui-même ses opérateurs basés sur le temps, donc bien que les connaissances que vous acquérez sur les générateurs et la gestion des effets secondaires dans ce style de gestionnaire de processus soient transférables, les opérateurs et l'utilisation réels ne sont utilisés dans aucune autre bibliothèque majeure. C'est donc un peu malheureux, mais cela ne devrait certainement pas être un facteur décisif en soi.

Il utilise également des "effets sous forme de données" ( décrits ici ), ce qui peut être difficile à comprendre au début, mais cela signifie que votre code redux-saga n'effectue pas réellement les effets secondaires lui-même. Au lieu de cela, les fonctions d'assistance que vous utilisez créent des objets qui sont comme des tâches qui représentent l'intention de faire l'effet secondaire, puis la bibliothèque interne l'exécute pour vous. Cela rend les tests extrêmement faciles, sans avoir besoin de se moquer et est très attrayant pour certaines personnes. Cependant, j'ai personnellement trouvé que cela signifie que vos tests unitaires réimplémentent une grande partie de la logique de votre saga - rendant ces tests pas très utiles IMO (cette opinion n'est pas partagée par tout le monde)

Les gens se demandent souvent pourquoi nous ne faisons pas quelque chose comme ça avec redux-observable: pour moi, c'est fondamentalement incompatible avec le Rx idiomatique normal. Dans Rx, nous utilisons des opérateurs comme .debounceTime()celui qui encapsule la logique requise pour anti-rebond, mais cela signifie que si nous voulions en créer une version qui n'effectue pas réellement le anti-rebond et émet à la place des objets de tâche avec l'intention, vous avez maintenant perdu le puissance de Rx parce que vous ne pouvez plus simplement enchaîner les opérateurs parce qu'ils opéreraient sur cet objet de tâche, pas sur le résultat réel de l'opération. C'est vraiment difficile à expliquer avec élégance. Cela nécessite encore une fois une compréhension approfondie de Rx pour comprendre l'incompatibilité des approches. Si vous voulez vraiment quelque chose comme ça, consultez redux-cyclesqui utilise cycle.js et a principalement ces objectifs. Je trouve que cela demande trop de cérémonie à mon goût, mais je vous encourage à lui donner un tour si cela vous intéresse.

Comme ThorbenA l'a mentionné, je n'hésite pas à admettre que redux-saga est actuellement (13/10/16) le leader incontesté de la gestion complexe des effets secondaires pour redux. Il a été lancé plus tôt et possède une communauté plus solide. Il y a donc beaucoup d'attrait à utiliser la norme de facto par rapport au nouvel enfant du quartier. Je pense qu'il est prudent de dire que si vous utilisez l'un ou l'autre sans connaissance préalable, vous êtes dans une certaine confusion. Nous utilisons tous les deux des concepts assez avancés qui, une fois que vous «obtenez», rendent la gestion complexe des effets secondaires beaucoup plus facile, mais jusque-là, beaucoup trébuchent.

Le conseil le plus important que je puisse donner est de ne pas importer l'une de ces bibliothèques avant d'en avoir besoin. Si vous ne faites que de simples appels ajax, vous n'en avez probablement pas besoin. redux-thunk est stupide et simple à apprendre et fournit assez pour les bases - mais plus l'async est complexe, plus il devient difficile (voire impossible) pour redux-thunk. Mais pour redux-observable / saga, à bien des égards, il brille d'autant plus que l'async est complexe. Il y a aussi beaucoup de mérite à utiliser redux-thunk avec l'un des autres (redux-observable / saga) dans le même projet! redux-thunk pour vos trucs simples communs et ensuite seulement utiliser redux-observable / saga pour des trucs complexes. C'est un excellent moyen de rester productif, donc vous ne combattez pas redux-observable / saga pour des choses qui seraient triviales avec redux-thunk.

Jayphelps
la source
3
Je viens de voir votre discours (uuhf le son!), Et appuyez immédiatement sur ⌘ + T + "redux-saga vs redux-observable". J'utilise redux-saga depuis un certain temps maintenant (en particulier dans React Native), mais après avoir regardé votre présentation et ce post, je peux voir quelques cas d'utilisation (pour moi) où redux-obs. serait en fait un meilleur ajustement. Votre exemple sur le fait d' debounceTime()avoir "perdu" le contrôle d'une logique très générique m'a frappé. Merci d'avoir expliqué.
Hulvej
3
Je viens de voir la conversation aussi et j'ai fait un peu plus de recherche sur Google. Bonne chose @jayphelps, merci pour le partage. J'aime particulièrement votre commentaire sur l'utilisation de redux-thunk en conjonction avec redux-observable / saga. Cela a beaucoup de sens, pourquoi trop compliquer les requêtes AJAX simples quand c'est inutile. Cela dit, il y a quelque chose à dire sur l'uniformité et la cohérence des gens. Merci encore!
Spets
Avant de passer à redux-saga / redux-observable, vous pouvez essayer redux-dispatch-listener et qui est très simple et peut déjà résoudre certains de vos cas d'utilisation: github.com/slorber/redux-dispatch-subscribe
Sebastien Lorber
C'était une réponse très utile. Je vous remercie! J'aime l'idée de pouvoir transférer les connaissances de RxJS vers d'autres domaines / frameworks.
Anselan
@jayphelps Quel serait un exemple de "complex async". J'essaie actuellement d'évaluer si je devrais passer du thunk à la saga / observables pour un projet. Merci :)
Sam Bokai
64

Je pense qu'il y a des choses dont vous devez tenir compte.

  1. Complexité
  2. Style de codage
  3. Courbe d'apprentissage
  4. Testabilité

Disons que nous voulons récupérer l'utilisateur de l'API

// 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'})
        )

Aussi, j'ai écrit cet article afin de comparer en profondeur les différences entre Redux-saga et Redux-Observable. Consultez ce lien ici ou la présentation .

Wayne Chiu
la source
3
cette comparaison côte à côte à partir du lien est excellente, merci
rofrol
1
J'adore la comparaison, MAIS il y a un problème que je veux soulever. Lorsque vous les comparez à l'aide d'appels API, vous utilisez fetch pour redux-observable. cool. MAIS, quand vous montrez des différences "annulables" .. vous n'utilisez PAS fetch - à la place vous utilisez le Observable.ajax interne ... pourquoi? Je préférerais le garder en utilisant "fetch" ou "axios". sinon, excellent travail là-bas.
james emanon
5
@jamesemanon Je suppose qu'il n'utilise pas fetch car Fetch API n'a pas encore la possibilité d'annuler. (plus à ce sujet: github.com/whatwg/fetch/issues/27 )
Daniel Andrei
Wow, cette comparaison approfondie avec tous les exemples est la meilleure. Je vous remercie!
Radek Matěj
22

J'utilise Redux-Observable sur Redux-Saga car je préfère travailler avec des observables sur des générateurs. Je l'utilise avec RXJS, qui est une bibliothèque puissante pour travailler avec des flux de données. Pensez-y comme un lodash pour async. En ce qui concerne les inconvénients, les pièges et les compromis dans le choix de l'un par rapport à l'autre, jetez un œil à cette réponse de Jay Phelps:

redux-saga en tant que projet existe depuis plus longtemps que redux-observable, c'est donc certainement un argument de vente majeur. Vous trouverez plus de documentation, des exemples et vous aurez probablement une meilleure communauté pour obtenir de l'aide.

Le contre est que les opérateurs et les API que vous apprenez dans redux-saga ne sont pas aussi transférables que l'apprentissage de RxJS, qui est utilisé partout. redux-observable est super super simple en interne, il vous donne vraiment un moyen naturel d'utiliser RxJS. Donc, si vous connaissez RxJS (ou que vous voulez), c'est un ajustement extrêmement naturel.

Mon conseil pour le moment à la plupart des gens est que si vous devez vous demander lequel utiliser, vous devriez probablement choisir redux-saga.

ThorbenA
la source
9

Redux-Observable est une bibliothèque incroyable, nous l'utilisons en production depuis 1,5 an sans aucun problème jusqu'à présent, elle est parfaitement testable et peut être facilement intégrée à n'importe quel framework. Nous avons des canaux de socket parallèles extrêmement surchargés et la seule chose qui nous évite les blocages est Redux-Observable

J'ai 3 points que je voudrais mentionner ici.

1. Complexité et courbe d'apprentissage

Redux-saga bat facilement redux-observable ici. Si vous avez besoin d'une simple demande d'autorisation et que vous ne voulez pas utiliser redux-thunk pour certaines raisons, vous devriez envisager d'utiliser redux-saga, c'est juste plus facile à comprendre.

Si vous n'avez pas de connaissance préalable d'Observable, ce sera pénible pour vous et votre équipe vous formera :)

2. Que peuvent m'offrir Observable et RxJS?

Quand il s'agit de logique asynchrone, Observable est votre couteau suisse, Observable peut littéralement tout faire pour vous. Vous ne devriez jamais les comparer à des promesses ou à des générateurs, c'est beaucoup plus puissant, c'est la même chose que de comparer Optimus Prime avec Chevrolet.

Et qu'en est-il de RxJS? C'est comme lodash.js mais pour la logique asynchrone, une fois que vous êtes entré, vous ne passerez jamais à quelque chose de différent.

3. Extension réactive

Vérifiez simplement ce lien

http://reactivex.io/languages.html

L'extension réactive est implémentée pour tous les langages de programmation modernes, c'est juste votre clé pour la programmation fonctionnelle.

Alors passez votre temps à bien apprendre RxJS et utilisez redux-observable :)

Denis Rybalka
la source
7

J'apprécie la transférabilité entre les langues et les environnements d'exécution de Rx. Même si votre application ne change pas de langue, votre carrière le peut. Tirez le meilleur parti de votre apprentissage, quelle que soit votre taille. C'est une excellente passerelle vers .Net LINQ en particulier.

Dean Radcliffe
la source
2
Choix intelligent, même si les générateurs sont également indépendants de la langue.
Greg Herbowicz
3

Puisqu'il y a tout un tas de discussions redux-observables ici, j'avais pensé que je donnerais le côté saga de l'argument. Je n'utilise pas redux-observable ou RxJS, donc je ne peux pas faire de comparaison côte à côte, mais j'ai utilisé des sagas avec beaucoup de succès.

Pour ce que ça vaut, j'utilise des sagas en production dans une application web.

Sagas contre Thunk

Saga gagne haut la main. Je n'ai pas aimé la façon dont Thunk a mis la logique dans mes créateurs d'action. Cela rendait également difficile de faire quelques demandes d'affilée. J'ai brièvement regardé redux-observable pour ce travail, mais je me suis installé sur Sagas.

Courbe d'apprentissage pour les sagas

Comprendre ce que sont les générateurs et pourquoi ils sont importants est essentiel pour comprendre les sagas. Mais je soulignerai que vous n'avez pas besoin de connaître les générateurs à l'intérieur et à l'extérieur. Vous devez seulement savoir que vous passez le contrôle avec l'instruction yield, et que la saga repassera le contrôle après la résolution de votre code asynchrone. Après cela, il n'est pas très difficile de comprendre ce qui se passe dans une saga.

Les méthodes de base de la saga sont (d'après mon expérience):

  • call- Appelez n'importe quel bit de code et obtenez la valeur de retour. Soutient les promesses. Grande synergie entre le traitement asynchrone et les sagas.
  • select- Appelez un sélecteur. Ce bit est plutôt brillant. Les sélecteurs sont au cœur de redux, et ils sont pris en charge à 100%!
  • put- aka dispatchune action. En fait, envoyez-en autant que vous le souhaitez!

Il y a d'autres fonctions, mais si vous pouvez maîtriser ces trois, vous serez dans un très bon endroit.

Conclusion

La raison pour laquelle j'ai choisi les sagas était la facilité d'utilisation. redux-observable ressemblait à un défi. Je suis satisfait à 100% des sagas. Plus heureux que je ne m'y attendais.

D'après mon expérience, les Sagas sont (bien) meilleures que les thunks et relativement faciles à comprendre. Rx n'est pas la tasse de thé de tout le monde. Je considérerais fortement les sagas au lieu de redux-observables si vous ne venez pas de cet écosystème et / ou ne prévoyez pas d'utiliser Rx à l'avenir.

Julius Ecker
la source
2

Si vous écrivez votre application dans Typescript, je vous recommande de vérifier sans type . Il est inspiré de Redux-Observable et dépend également de RxJS, mais il existe tout l'écosystème pour créer l'application.

Les plus gros inconvénients de redux-observable / redux-saga sont le manque de directives. Il n'y a pas de directives officielles sur la façon de paresser les réducteurs de charge, les sagas ou les épopées. Le fractionnement du code est essentiel lors de la mise à l'échelle d'applications plus volumineuses. Les solutions personnalisées pour le chargement différé ne fonctionnent généralement pas avec HMR, ce qui entraîne une mauvaise expérience des développeurs.

Avantages typés:

  1. Conçu pour TypeScript
    Toutes les API sont conçues pour la dactylographie et la sécurité de type:
    • Typescript augmentera votre productivité, pas vous ralentira.
    • Seules les annotations nécessaires sont requises: état, arguments d'action.
    • Pas de typage. Tout est déduit automatiquement. 95% du code ressemble à du javascript pur.
    • Pas de RootAction, RootEpic, RootState ou d'autres types d'assistance.
  2. Fournir tous les blocs de construction
    • Typeless inclut tout pour créer des applications de taille moyenne ou d'entreprise.
    • Vous n'avez pas besoin de vous fier à plusieurs petites bibliothèques.
  3. Modularité
    • Une bonne modularité est essentielle pour créer des applications évolutives.
    • Il n'est pas nécessaire de créer des fichiers racine pour les epics, les réducteurs, les types, etc. Une fois que vous avez créé un nouveau module, vous pouvez le joindre à partir de n'importe quel endroit. Similaire aux composants React standard.
  4. Dogmatique
    • Tous les cas d'utilisation et problèmes courants sont résolus par défaut. Pas besoin de trop réfléchir à la façon de résoudre les problèmes insignifiants.
    • Toutes les recommandations et bonnes pratiques sont fournies!

Découvrez https://typeless.js.org/

ciel
la source
1
Vous devez ajouter une clause de non-responsabilité lorsque vous recommandez un logiciel dont vous êtes le principal contributeur.
Hagelt18