¿Por qué usar Redux-Observable sobre Redux-Saga?


133

He usado Redux-Saga . El código escrito con él es fácil de razonar hasta ahora, excepto que la función del generador JS me está arruinando la cabeza de vez en cuando. Según tengo entendido, Redux-Observable puede lograr el trabajo similar que maneja los efectos secundarios pero sin usar la función de generador.

Sin embargo, los documentos de Redux-Observable no proporcionan muchas opiniones de por qué es superior contra Redux-Saga. Me gustaría saber si no usar la función de generador es el único beneficio de usar Redux-Observable. ¿Y cuáles podrían ser los inconvenientes, problemas o compromisos del uso de Redux-Observable en lugar de Redux-Saga? Gracias por adelantado.


Hice un blog divertido pero detallado donde encontré que Redux-Saga es superior a Redux-Observable para las personas que no viven / comen / respiran observables en todo el día. Estoy seguro de que es genial si toda tu pila es observable. shift.infinite.red/…
Gant Laborde

Respuestas:


236

Descargo de responsabilidad: soy uno de los autores de redux-observable, por lo que es difícil para mí ser 100% imparcial.

Actualmente no proporcionamos ninguna razón por la que redux-observable sea mejor que redux-saga porque ... no lo es. 😆

tl; dr hay pros y contras para ambos. Muchos encontrarán uno más intuitivo que el otro, pero ambos son complejos de aprender de diferentes maneras si no conoce RxJS (redux-observable) o generadores / "efectos como datos" (redux-saga).

Resuelven el mismo problema de maneras extremadamente similares, pero tienen algunas diferencias fundamentales que solo se vuelven realmente aparentes una vez que las usas lo suficiente.

redux-observable difiere casi todo a RxJS idiomático. Entonces, si tiene conocimiento de RxJS (o lo obtiene), aprender y usar redux-observable es súper natural. Eso también significa que este conocimiento es transferible a otras cosas que no sean redux. Si decide cambiarse a MobX, si decide cambiar a Angular2, si decide cambiar a algo atractivo futuro X, es muy probable que RxJS pueda ayudarlo. Esto se debe a que RxJS es una biblioteca asíncrona genérica y, en muchos sentidos, es como un lenguaje de programación en sí mismo: todo el paradigma de "Programación reactiva". RxJS existió desde 2012 y comenzó como un puerto de Rx.NET (hay "puertos" en casi todos los idiomas principales, es muy útil ).

redux-saga proporciona sus propios operadores basados ​​en el tiempo, por lo que si bien el conocimiento que adquiere sobre los generadores y el manejo de los efectos secundarios en este estilo de administrador de procesos es transferible, los operadores y el uso reales no se utilizan en ninguna otra biblioteca importante. Eso es un poco desafortunado, pero ciertamente no debería ser un factor decisivo en sí mismo.

También utiliza "efectos como datos" ( descritos aquí ), que pueden ser difíciles de entender al principio, pero significa que su código redux-saga en realidad no realiza los efectos secundarios. En cambio, las funciones de ayuda que usa crean objetos que son como tareas que representan la intención de hacer el efecto secundario y luego la biblioteca interna lo realiza por usted. Esto hace que las pruebas sean extremadamente fáciles, sin necesidad de burlarse y es muy atractivo para algunas personas. Sin embargo, personalmente he descubierto que significa que las pruebas de su unidad vuelven a implementar gran parte de la lógica de su saga, lo que hace que esas pruebas no sean muy útiles en mi opinión (esta opinión no es compartida por todos)

La gente a menudo pregunta por qué no hacemos algo así con redux-observable: para mí es fundamentalmente incompatible con la Rx idiomática normal. En Rx, utilizamos operadores como .debounceTime()esos que encapsulan la lógica requerida para eliminar el rebote, pero eso significa que si quisiéramos hacer una versión del mismo que en realidad no realice el rebote y en su lugar emita objetos de tarea con la intención, ahora ha perdido el poder de Rx porque ya no puedes simplemente encadenar operadores porque estarían operando en ese objeto de tarea, no el resultado real de la operación. Esto es realmente difícil de explicar con elegancia. Nuevamente requiere una gran comprensión de Rx para comprender la incompatibilidad de los enfoques. Si realmente quieres algo así, echa un vistazo a redux-cyclesque usa cycle.js y tiene principalmente esos objetivos. Creo que requiere demasiada ceremonia para mis gustos, pero te animo a que le des un giro si te interesa.

Como ThorbenA mencionó, no rehuyo admitir que redux-saga es actualmente (13/10/16) el claro líder en la gestión de efectos secundarios complejos para redux. Se inició antes y tiene una comunidad más sólida. Por lo tanto, hay una gran atracción al usar el estándar de facto sobre el nuevo chico en el bloque. Creo que es seguro decir que si usas cualquiera de ellos sin conocimiento previo, te encontrarás con cierta confusión. Ambos usamos conceptos bastante avanzados que una vez que "entiendes", hace que la gestión de efectos secundarios sea mucho más fácil, pero hasta entonces muchos tropiezan.

El consejo más importante que puedo dar es que no traiga ninguna de estas bibliotecas antes de que las necesite. Si solo está haciendo llamadas simples ajax, probablemente no las necesite. redux-thunk es estúpido, fácil de aprender y proporciona lo básico para lo básico, pero cuanto más complejo es el asíncrono, más difícil (o incluso imposible) se vuelve para redux-thunk. Pero para redux-observable / saga de muchas maneras, brilla más cuanto más complejo es el asíncrono. ¡También hay mucho mérito en usar redux-thunk con uno de los otros (redux-observable / saga) en el mismo proyecto! redux-thunk para tus cosas simples comunes y luego solo usando redux-observable / saga para cosas complejas. Esa es una excelente manera de seguir siendo productivo, por lo que no estás luchando contra redux-observable / saga por cosas que serían triviales con redux-thunk.


3
Acabo de ver tu charla (¡uhhf el sonido!), E inmediatamente presionó ⌘ + T + "redux-saga vs redux-observable". He usado redux-saga desde hace bastante tiempo (especialmente en React Native), pero después de haber visto su charla y esta publicación, puedo ver algunos casos de uso (para mí) donde redux-obs. En realidad sería un mejor ajuste. Su ejemplo sobre debounceTime()y haber "perdido" el control sobre una lógica muy genérica me golpeó. Gracias por la explicación.
Hulvej

3
Acabo de ver la charla también y busqué un poco más en Google. Buenas cosas @jayphelps, gracias por compartir. Me gusta especialmente su comentario sobre el uso de redux-thunk junto con redux-observable / saga. Eso tiene mucho sentido, por qué complicar demasiado las solicitudes simples de AJAX cuando es innecesario. Dicho esto, hay algo que decir sobre la uniformidad y mantener a las personas consistentes. ¡Gracias de nuevo!
Pasa el

Antes de actualizar a redux-saga / redux-observable, puede probar redux-dispatch-listener y que es muy simple y ya puede resolver algunos de sus casos de uso: github.com/slorber/redux-dispatch-subscribe
Sebastien Lorber

Esta fue una respuesta muy útil. ¡Gracias! Me gusta el punto de poder transferir el conocimiento de RxJS a otros dominios / marcos.
Anselan

@jayphelps ¿Cuál sería un ejemplo de "asincrónica compleja"? Actualmente tratando de evaluar si debo cambiar de thunk a saga / observables para un proyecto. Gracias :)
Sam Bokai

64

Creo que hay cosas que debes tener en cuenta.

  1. Complejidad
  2. Estilo de codificación
  3. Curva de aprendizaje
  4. Testabilidad

Digamos que queremos obtener usuarios de la 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'})
        )

Además, he escrito este artículo para comparar en profundidad las diferencias entre Redux-saga y Redux-Observable. Echa un vistazo a este enlace aquí o presentación .


3
esta comparación lado a lado del enlace es genial, gracias
rofrol

1
Me encanta la comparación, PERO hay un problema que quiero mencionar. Cuando los compara usando llamadas api, está usando fetch para redux-observable. frio. PERO, cuando muestra diferencias "cancelables" ... NO usa fetch - en su lugar usa el Observable.ajax interno ... ¿por qué? Prefiero mantenerlo usando "fetch" o "axios". de lo contrario, gran trabajo allí.
James Emanon

55
@jamesemanon Supongo que no está usando fetch porque fetch API aún no tiene la opción de cancelar. (más sobre esto: github.com/whatwg/fetch/issues/27 )
Daniel Andrei

Wow, esa comparación en profundidad con todos los ejemplos es la mejor. ¡Gracias!
Radek Matěj

22

Utilizo Redux-Observable sobre Redux-Saga porque prefiero trabajar con observables sobre generadores. Lo uso con RXJS, que es una biblioteca poderosa para trabajar con flujos de datos. Piense en ello como lodash para asíncrono. En términos de inconvenientes, problemas y compromisos al elegir uno sobre el otro, eche un vistazo a esta respuesta de Jay Phelps:

redux-saga como proyecto ha existido por más tiempo que redux-observable, por lo que ese es sin duda uno de los principales puntos de venta. Encontrará más documentación, ejemplos y es probable que tenga una mejor comunidad para obtener apoyo.

La respuesta es que los operadores y las API que aprende en redux-saga no son tan transferibles como aprender RxJS, que se usa en todas partes. redux-observable es súper súper súper simple internamente, en realidad solo te brinda una forma natural de usar RxJS. Entonces, si conoce RxJS (o quiere), es un ajuste extremadamente natural.

Mi consejo en este momento para la mayoría de las personas es que si tienes que preguntar cuál debes usar, probablemente deberías elegir redux-saga.


9

Redux-Observable es una biblioteca increíble, la utilizamos en producción durante 1,5 años sin ningún problema hasta ahora, es perfectamente comprobable y se puede integrar fácilmente con cualquier marco. Estamos teniendo canales de socket paralelos extremadamente sobrecargados y lo único que nos está salvando de las congelaciones es Redux-Observable

Tengo 3 puntos que me gustaría mencionar aquí.

1. Complejidad y curva de aprendizaje.

Redux-saga supera fácilmente a redux-observable aquí. Si solo necesita una simple solicitud para obtener la autorización y no desea usar redux-thunk por alguna razón, debe considerar usar redux-saga, es más fácil de entender.

Si no tienes conocimiento previo de Observable, será un dolor para ti y tu equipo te seguirá :)

2. ¿Qué pueden ofrecerme Observable y RxJS?

Cuando se trata de lógica asíncrona, Observable es su cuchillo suizo, Observable puede hacer literalmente casi todo por usted. Nunca debe compararlos con promesas o generadores, es mucho más poderoso, es lo mismo que comparar Optimus Prime con Chevrolet.

¿Y qué hay de RxJS? Es como lodash.js, pero para la lógica asíncrona, una vez que entras, nunca cambiarás a algo diferente.

3. Extensión reactiva

Solo revisa este enlace

http://reactivex.io/languages.html

La extensión reactiva se implementa para todos los lenguajes de programación modernos, es solo su clave para la programación funcional.

Así que dedique su tiempo sabiamente a aprender RxJS y use redux-observable :)


7

Valoro la transferibilidad entre idiomas y tiempos de ejecución que tiene Rx. Incluso si su aplicación no cambiará de idioma, su carrera puede hacerlo. Obtenga el mejor apalancamiento posible en su aprendizaje, sin importar cómo lo evalúe usted mismo. Es una gran puerta de entrada a .Net LINQ en particular.


2
Elección inteligente, aunque los generadores también son independientes del lenguaje.
Greg Herbowicz

3

Como hay un montón de charla observable redux aquí, pensé en darle el lado de la saga al argumento. No uso redux-observable o RxJS, por lo que no puedo hacer una comparación lado a lado, pero he usado sagas con gran efecto.

Por lo que vale, estoy usando sagas en producción en una aplicación web.

Sagas vs. Thunk

Saga gana sin dudas. No me gustó cómo thunk puso lógica en mis creadores de acción. También hizo que hacer algunas solicitudes seguidas fuera problemático. Miré brevemente a redux-observable para este trabajo, pero me decidí por Sagas.

Curva de aprendizaje para sagas

Comprender qué son los generadores y por qué son importantes es clave para comprender las sagas. Pero enfatizaré que no necesita conocer generadores por dentro y por fuera. Solo necesita saber que está pasando el control con la declaración de rendimiento, y que la saga le devolverá el control después de que se resuelva su código asíncrono. Después de ese momento, no es muy difícil entender lo que sucede en una saga.

Los métodos principales de la saga son (en mi experiencia):

  • call- Llame a cualquier bit de código y obtenga el valor de retorno. Apoya las promesas. Gran sinergia entre procesamiento asíncrono y sagas.
  • select- Llamar a un selector. Este bit es bastante brillante. ¡Los selectores son esenciales para redux, y son 100% compatibles!
  • put- Alias dispatchuna acción. De hecho, ¡despacha tantos como quieras!

Hay otras funciones, pero si puedes dominar esas tres, estarás en un lugar realmente bueno.

Conclusión

La razón por la que elegí las sagas fue la facilidad de uso. redux-observable parecía un desafío. Estoy 100% satisfecho con las sagas. Más feliz de lo que esperaba.

En mi experiencia, las sagas son (mucho) mejores que los thunks y relativamente fáciles de entender. Rx no es la taza de té de todos. Consideraría fuertemente las sagas en lugar de las redux-observables si no vienes de ese ecosistema y / o no planeas usar Rx en el futuro.


2

Si escribe su aplicación a máquina de escribir, recomiendo la comprobación sin tipo . Está inspirado en Redux-Observable, y también depende de RxJS, pero existe todo el ecosistema para construir la aplicación.

Los mayores inconvenientes de redux-observable / redux-saga son la falta de pautas. No hay pautas oficiales sobre cómo reducir la carga perezosa, sagas o epopeyas. La división de código es crítica al escalar aplicaciones más grandes. Las soluciones personalizadas para la carga diferida generalmente no funcionan con HMR, lo que causa una mala experiencia del desarrollador.

Profesionales sin tipo:

  1. Diseñado para TypeScript
    Todas las API están diseñadas para typecript y type-safety:
    • Typecript aumentará su productividad, no lo ralentizará.
    • Solo se requieren las anotaciones necesarias: estado, argumentos de acción.
    • Sin encasillamiento. Todo se infiere automáticamente. El 95% del código parece puro javascript.
    • No RootAction, RootEpic, RootState u otros tipos de ayuda.
  2. Proporcionar todos los bloques de construcción.
    • Typeless incluye todo para construir aplicaciones medianas o de nivel empresarial.
    • No necesita confiar en múltiples bibliotecas pequeñas.
  3. Modularidad
    • La modularidad adecuada es fundamental para crear aplicaciones escalables.
    • No es necesario crear archivos raíz para epopeyas, reductores, tipos, etc. Una vez que cree un nuevo módulo, puede adjuntarlo desde cualquier lugar. Similar a los componentes React estándar.
  4. Dogmático
    • Todos los casos y problemas de uso comunes se resuelven por defecto. No es necesario pensar demasiado en cómo solucionar problemas triviales.
    • Se proporcionan todas las recomendaciones y mejores prácticas.

Echa un vistazo a https://typeless.js.org/


1
Debería agregar un descargo de responsabilidad al recomendar el software para el que es el principal contribuyente.
Hagelt18
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.