Por que usar Redux-Observable sobre Redux-Saga?

133

Eu usei Redux-Saga . O código escrito com ele é fácil de raciocinar até agora, exceto que a função de gerador JS está atrapalhando minha cabeça de vez em quando. Pelo meu entendimento, o Redux-Observable pode realizar um trabalho semelhante que lida com efeitos colaterais, mas sem usar a função de gerador.

No entanto, os documentos do Redux-Observable não fornecem muitas opiniões sobre por que é superior ao Redux-Saga. Gostaria de saber se o não uso da função gerador é o único benefício do Redux-Observable. E quais poderiam ser as desvantagens, problemas ou comprometimentos do uso do Redux-Observable em vez do Redux-Saga? Desde já, obrigado.

Ivan Wang
fonte
Eu tinha feito um blog divertido, mas detalhado, onde achei o Redux-Saga superior ao Redux-Observable para pessoas que não vivem / comem / respiram observáveis ​​o dia todo. Tenho certeza que é ótimo se toda a sua pilha for observável. shift.infinite.red/…
Gant Laborde

Respostas:

236

Isenção de responsabilidade: Eu sou um dos autores de redux observable, por isso é difícil para mim ser 100% imparcial.

Atualmente, não fornecemos nenhum motivo para que o redux-observable seja melhor que o redux-saga porque ... não é. 😆

tl; dr existem prós e contras para ambos. Muitos acharão um mais intuitivo que o outro, mas ambos são complexos para aprender de maneiras diferentes, se você não conhece RxJS (observável em redux) ou geradores / "efeitos como dados" (saga de redux).

Eles resolvem o mesmo problema de maneiras extremamente semelhantes, mas têm algumas diferenças fundamentais que só se tornam verdadeiramente aparentes quando você as usa o suficiente.

observável em redux adia quase tudo ao RxJS idiomático. Portanto, se você tem conhecimento de RxJS (ou obtém), aprender e usar o redux observável é super super natural. Isso também significa que esse conhecimento é transferível para outras coisas que não o redux. Se você optar por mudar para o MobX, se você optar por mudar para o Angular2, se você decidir mudar para algum gostinho futuro X, as chances são extremamente boas de que o RxJS possa ajudá-lo. Isso ocorre porque o RxJS é uma biblioteca assíncrona genérica e, de várias maneiras, é como uma linguagem de programação em si - todo o paradigma "Programação Reativa". O RxJS existe desde 2012 e começou como uma porta do Rx.NET (existem "portas" em quase todos os principais idiomas, é tão útil ).

O redux-saga fornece seus próprios operadores baseados em tempo, portanto, embora o conhecimento que você adquira sobre geradores e manuseie efeitos colaterais nesse estilo de gerenciador de processos seja transferível, os operadores e o uso reais não são usados ​​em nenhuma outra biblioteca importante. Então isso é um pouco lamentável, mas certamente não deve ser um rompimento de acordos por si só.

Ele também usa "efeitos como dados" ( descritos aqui ), o que pode ser difícil de entender inicialmente, mas significa que o código da redux-saga não realiza os efeitos colaterais propriamente ditos. Em vez disso, as funções auxiliares usadas criam objetos que são como tarefas que representam a intenção de causar o efeito colateral e, em seguida, a biblioteca interna o executa para você. Isso torna os testes extremamente fáceis, sem a necessidade de zombaria e é muito atraente para algumas pessoas. No entanto, eu pessoalmente achei que isso significa que seus testes de unidade reimplementam grande parte da lógica da sua saga - tornando esses testes pouco úteis para IMO (essa opinião não é compartilhada por todos)

As pessoas frequentemente perguntam por que não fazemos algo assim com redux observável: para mim é fundamentalmente incompatível com o Rx idiomático normal. No Rx, usamos operadores como .debounceTime()esse que encapsulam a lógica necessária para rebater, mas isso significa que, se quiséssemos fazer uma versão dela que na verdade não executa a depuração e emite objetos de tarefa com a intenção, você agora perdeu o poder do Rx porque você não pode mais encadear operadores porque eles operariam nesse objeto de tarefa, não no resultado real da operação. É realmente difícil de explicar de maneira elegante. Mais uma vez, é necessário um forte entendimento de Rx para entender a incompatibilidade de abordagens. Se você realmente quer algo assim, confira os ciclos de reduxque usa o cycle.js e tem principalmente esses objetivos. Acho que exige muita cerimônia para o meu gosto, mas encorajo você a dar uma volta, se for do seu interesse.

Como ThorbenA mencionou, eu não evito admitir que o redux-saga é atualmente (13/10/16) o líder claro no gerenciamento complexo de efeitos colaterais do redux. Foi iniciado anteriormente e tem uma comunidade mais robusta. Portanto, há muita atração em usar o padrão de fato sobre o novo garoto do quarteirão. Eu acho que é seguro dizer que, se você usa ou sem conhecimento prévio, você está confuso. Nós dois usamos conceitos bastante avançados que, quando você "obtém", facilitam muito o gerenciamento complexo de efeitos colaterais, mas até então muitos tropeçam.

O conselho mais importante que posso dar é não trazer nenhuma dessas bibliotecas antes que você precise delas. Se você está fazendo apenas chamadas ajax simples, provavelmente não precisa delas. redux-thunk é estúpido, simples de aprender e fornece o suficiente para o básico - mas quanto mais complexo o assíncrono, mais difícil (ou até impossível) se torna para o redux-thunk. Mas, para o redux observável / saga, de muitas maneiras, ele brilha tanto quanto mais complexo é o assíncrono. Também há muito mérito em usar o redux-thunk com um dos outros (redux-observable / saga) no mesmo projeto! redux-thunk para coisas simples e comuns e, em seguida, use apenas redux-observable / saga para coisas complexas. Essa é uma ótima maneira de permanecer produtivo, para que você não esteja lutando com redux-observable / saga por coisas que seriam triviais com redux-thunk.

jayphelps
fonte
3
Acabei de ver sua palestra (uuhf, o som!) E imediatamente pressione ⌘ + T + "redux-saga vs redux-observable". Eu uso o redux-saga há algum tempo agora (especialmente no React Native), mas depois de assistir a sua palestra e deste post, posso ver alguns casos de uso (para mim) em que o redux-obs. seria realmente um ajuste melhor. Seu exemplo sobre debounceTime()e ter "perdido" o controle sobre uma lógica muito genérica meio que foi atingido por mim. Obrigado por explicar.
Hulvej
3
Só vi a conversa e fiz um pouco mais de pesquisa no Google. Coisas boas @jayphelps, obrigado por compartilhar. Gosto especialmente do seu comentário usando redux-thunk em conjunto com redux-observable / saga. Isso faz muito sentido, por que complicar solicitações simples de AJAX quando desnecessário. Dito isto, há algo a ser dito para uniformizar e manter as pessoas consistentes. Obrigado novamente!
Spets 03/07
Antes de atualizar para redux-saga / redux-observable, você pode tentar redux-dispatch-listener e que é muito simples e já pode resolver alguns de seus casos de uso: github.com/slorber/redux-dispatch-subscribe
Sebastien Lorber,
Esta foi uma resposta muito útil. Obrigado! Gosto da questão de poder transferir conhecimento do RxJS para outros domínios / estruturas.
Anselan
@ jayphelps O que seria um exemplo de "assíncrono complexo". Atualmente, tentando avaliar se devo mudar de thunk para saga / observables para um projeto. Obrigado :)
Sam Bokai
64

Eu acho que há coisas que você precisa levar em consideração.

  1. Complexidade
  2. Estilo de codificação
  3. Curva de aprendizado
  4. Testabilidade

Digamos que queremos buscar o usuário na 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'})
        )

Além disso, escrevi este artigo para comparar as diferenças entre Redux-saga e Redux-Observable em profundidade. Confira este link aqui ou apresentação .

Wayne Chiu
fonte
3
este lado-a-lado-de comparação a partir do link é grande, graças
rofrol
1
Eu amo a comparação, mas há um problema com o qual eu quero falar. Quando você os compara usando chamadas da API - você está usando a busca para observar o redux. legal. MAS, quando você mostra diferenças "canceláveis" ... você NÃO usa a busca - em vez disso, usa o Observable.ajax interno ... por quê? Eu preferiria mantê-lo usando "buscar" ou "axios". caso contrário, ótimo trabalho lá.
james Emanon
5
@jamesemanon Presumo que ele não esteja usando a busca porque a API de busca ainda não tem a opção de cancelar. (mais sobre isso: github.com/whatwg/fetch/issues/27 )
Daniel Andrei
Uau, essa comparação detalhada com todos os exemplos é a melhor. Obrigado!
Radek Matěj
22

Eu uso o Redux-Observable sobre o Redux-Saga, porque prefiro trabalhar com observáveis ​​do que com geradores. Eu o uso com o RXJS, que é uma biblioteca poderosa para trabalhar com fluxos de dados. Pense nisso como lodash para async. Em termos de desvantagens, problemas e compromissos na escolha de um sobre o outro, dê uma olhada nesta resposta de Jay Phelps:

redux-saga como um projeto já existe há mais tempo que o redux-observável, então esse é certamente um dos principais pontos de venda. Você encontrará mais documentação, exemplos e provavelmente terá uma comunidade melhor para obter suporte.

O contador é que os operadores e APIs que você aprende na redux-saga não são tão transferíveis quanto aprender o RxJS, que é usado em todo o lugar. O redux-observable é super super super simples internamente, é realmente apenas uma maneira natural de você usar o RxJS. Portanto, se você conhece o RxJS (ou deseja), é um ajuste extremamente natural.

Meu conselho no momento para a maioria das pessoas é que, se você precisar perguntar qual delas deve usar, provavelmente deverá escolher redux-saga.

ThorbenA
fonte
9

O Redux-Observable é uma biblioteca incrível, nós a usamos em produção por 1,5 anos sem problemas até o momento, é perfeitamente testável e pode ser facilmente integrado a qualquer estrutura. Estamos tendo canais de soquete paralelos extremamente sobrecarregados e a única coisa que nos impede de congelamentos é o Redux-Observable

Eu tenho 3 pontos que gostaria de mencionar aqui.

1. Complexidade e curva de aprendizado

Redux-saga supera facilmente o redux-observável aqui. Se você precisar de apenas uma solicitação simples para obter a autorização e não quiser usar o redux-thunk por alguns motivos, considere usar o redux-saga, é mais fácil de entender.

Se você não tem conhecimento prévio do Observable, será uma dor para você e sua equipe o acompanhará :)

2. O que o Observable e o RxJS podem me oferecer?

Quando se trata de lógica assíncrona, o Observable é a sua faca suíça, o Observable pode literalmente fazer quase tudo por você. Você nunca deve compará-los a promessas ou geradores, pois é muito mais poderoso, é o mesmo que comparar o Optimus Prime com a Chevrolet.

E o RxJS? É como o lodash.js, mas para a lógica assíncrona, uma vez que você entrar nunca mudará para algo diferente.

3. Extensão reativa

Basta verificar este link

http://reactivex.io/languages.html

A extensão reativa é implementada para todas as linguagens de programação modernas, é apenas a sua chave para a programação funcional.

Portanto, gaste seu tempo sabiamente aprendendo RxJS e use redux-observable :)

Denis Rybalka
fonte
7

Eu valorizo ​​a transferibilidade entre idiomas e tempos de execução que o Rx possui. Mesmo que seu aplicativo não mude de idioma, sua carreira pode. Obtenha a melhor alavancagem possível no seu aprendizado, no entanto, você avalia isso por si mesmo. É uma excelente porta de entrada para o .Net LINQ em particular.

Dean Radcliffe
fonte
2
Escolha inteligente, embora os geradores também sejam independentes de idioma.
precisa saber é o seguinte
3

Já que há um monte de conversas observáveis ​​em redux aqui, eu pensei em dar o lado da saga da discussão. Eu não uso redux-observable ou RxJS, então não posso fazer uma comparação lado a lado, mas usei sagas com grande efeito.

Pelo que vale, estou usando sagas na produção em um aplicativo da web.

Sagas vs. Thunk

Saga ganha as mãos para baixo. Não gostei de como o thunk colocou a lógica em meus criadores de ação. Também fez com que alguns pedidos seguidos fossem problemáticos. Olhei brevemente para o redux observável para este trabalho, mas decidi por Sagas.

Curva de Aprendizagem para Sagas

Entender o que são geradores e por que são importantes é fundamental para entender as sagas. Mas vou enfatizar que você não precisa conhecer geradores por dentro e por fora. Você só precisa saber que está passando o controle com a declaração de rendimento e que a saga passará o controle novamente após a resolução do código assíncrono. Depois disso, não é muito difícil entender o que está acontecendo em uma saga.

Os métodos principais da saga são (na minha experiência):

  • call- Ligue para qualquer parte do código e obtenha o valor de retorno. Suporta promessas. Grande sinergia entre processamento assíncrono e sagas.
  • select- Ligue para um seletor. Este pedaço é bastante brilhante. Os seletores são essenciais para o redux e são 100% suportados!
  • put- aka dispatchuma ação. De fato, envie quantas quiser!

Existem outras funções, mas se você conseguir dominar essas três, estará em um lugar muito bom.

Conclusão

A razão pela qual escolhi as sagas foi a facilidade de uso. redux-observable parecia um desafio. Estou 100% satisfeito com as sagas. Mais feliz do que eu esperava.

Na minha experiência, as sagas são (muito) melhores do que thunks e relativamente fáceis de entender. Rx não é a xícara de chá de todos. Eu consideraria fortemente as sagas em vez de observáveis ​​no redux se você não vier desse ecossistema e / ou não planeja usar o Rx no futuro.

Julius Ecker
fonte
2

Se você escrever seu aplicativo no Typescript, recomendo verificar o tipo de letra . É inspirado no Redux-Observable e também depende do RxJS, mas existe todo o ecossistema para a criação do aplicativo.

Os maiores contras da redux-observable / redux-saga são a falta de diretrizes. Não há diretrizes oficiais sobre como carregar redutores de carga preguiçosos, sagas ou épicos. A divisão de código é crítica ao dimensionar aplicativos maiores. Soluções personalizadas para carregamento lento normalmente não funcionam com o HMR, causando pouca experiência ao desenvolvedor.

Profissionais sem nome:

  1. Projetado para TypeScript
    Todas as APIs são projetadas para segurança de texto e de texto :
    • O texto datilografado aumentará sua produtividade, não o tornará mais lento.
    • Somente as anotações necessárias são necessárias: estado, argumentos de ação.
    • Nenhuma impressão. Tudo é inferido automaticamente. 95% do código parece javascript puro.
    • Nenhum RootAction, RootEpic, RootState ou outros tipos de auxiliar.
  2. Forneça todos os blocos de construção
    • O Typeless inclui tudo para criar aplicativos de tamanho médio ou corporativo.
    • Você não precisa confiar em várias bibliotecas pequenas.
  3. Modularidade
    • A modularidade adequada é fundamental para a criação de aplicativos escaláveis.
    • Não há necessidade de criar arquivos raiz para épicos, redutores, tipos etc. Depois de criar um novo módulo, você pode anexá-lo de qualquer lugar. Semelhante aos componentes padrão do React.
  4. Opinião
    • Todos os casos de uso e problemas comuns são resolvidos por padrão. Não há necessidade de pensar demais em como corrigir problemas triviais.
    • Todas as recomendações e melhores práticas são fornecidas!

Confira https://typeless.js.org/

céu
fonte
1
Você deve adicionar um aviso ao recomendar o software para o qual você é o principal colaborador.
Hagelt18