3 anos de React/Redux, agora entendo Sagas
Em conjunto com o tema de “Separation of Concerns” do vídeo do Filipe Deschamps, tive a oportunidade de aplicar na prática uma biblioteca bem útil que muitos já conhecem, Redux Saga.
E antes mesmo de adicioná-la no projeto, após ler um pouco da documentação, pensei nas consequências:
- Mais uma biblioteca
- Mais uma depêndencia
- Mais um arquivo sagas.js pra cada módulo do redux
- Function Generators?
Talvez fosse mais do que muitos projetos precisam, mas fui atrás de usá-la e testá-la sem preconceitos, até por que nenhuma biblioteca no npm/yarn chega a 19k de stars (no momento da publicação desse artigo) no GitHub por nada.
A frase de impacto que a ferramenta usa para que você a leve em consideração é a seguinte:
redux-saga is a library that aims to make application side effects easier to manage…
e por side effects você deve imaginar que são chamadas para uma API Rest ou guardar dados no LocalStorage (ou AsyncStorage se estiver no React Native), certo?
Sim! Porém, caso você já tenha mexido no redux anteriormente, deve estar pensando: Mas e o redux-thunk? Não faz a mesma coisa? Preciso usar as sagas junto com as thunks? ou nem preciso das thunks?
Pois bem, na própria documentação do redux-thunk nos deparamos com o por que de usá-la também:
Thunks are… and simple async logic like AJAX requests.
Novamente em Javascript caímos na armadilha de existirem 2 ou mais bibliotecas para resolver o mesmo problema, a diferença é que nesse caso as duas soluções estão atreladas ao Redux (que já é complicado de entender de primeira).
Caso você esteja começando um projeto novo, recomendo que tente sair da zona de conforto mais uma vez e utilize redux-saga ao invés de redux-thunk. Até porque o redux-saga tem uma documentação mais completa por resolver mais problemas que o redux-thunk e, por usar Function Generators, definitivamente consegue ir muito além de um simples async/await, e facilita o desenvolvimento de funcionalidades um pouco chatas de escrever na mão como por exemplo:
- Throttling
- Debouncing
- Tentar novamente chamadas falhas para API (você pode determinar quantas vezes a api deve ser chamada até que a saga pare as tentativas) a partir do helper
retry - Desfazer ações (como no Gmail, quando você apaga algum e-mail e uma notificação aparece para que você desfaça essa ação).
- Execução de várias chamadas para api ao mesmo tempo a partir do helper
takeEveryou até mesmo cancelar chamadas consecutivas e aceitar apenas a última a partir do helpertakeLatest
Claro que dá pra fazer tudo isso com thunks, mas o que estou levando em consideração aqui é a facilidade de criar funcionalidades como essas, e sim: Pagamos por essa facilidade no tamanho do bundle final da aplicação.
Mas leve em consideração o tempo de criação/adoção/testes para escrita de funcionalidades como essas e logo você vai perceber que vale a pena adicionar mais uma dependência no seu projeto, ao invés de reinventar a roda.
A palavra chave aqui é produtividade.
Nota: Pra quem não tem conhecimento e/ou não está acostumado com a escrita de funções que retornam outras funções (como nas thunks) ou da escrita de funções como essa em sagas:
function* justDoIt() {
yield something();
}terá dificuldade pra entender o fluxo proposto por essas tecnologias.
Ou seja, de qualquer jeito o seu time vai ter que se acostumar um novo padrão de escrita, então opte pela biblioteca certa porque migrar de uma pra outra ou usar as duas ao mesmo tempo vai causar um desconforto de qualquer jeito.
Apesar do desconforto, acredito que valha a pena aprender esses dois padrões um hora ou outra em algum momento na sua carreira. Esses padrões vão te abrir portas pra refatorar código que você nem imagina.
Então bora pra alguns exemplos de código para entendermos algumas diferenças:
E aí, diferente ne? Os dois códigos acima tem exatamente o mesmo efeito,
- Executar uma chamada para uma api passando o id de um usuário
- Executar uma action para armazenar esse usuário no estado do Redux
mas sem saber exatamente o contexto em que essa função percente, ficam as perguntas:
- Qual você acha mais simples?
- Um novo desenvolver que está entrando no seu time vai entender de primeira?
- E alguém que já tenha experiência com redux?
Quem já trabalhou comigo sabe que eu me importo muito com um conceito conhecido como DX (Developer Experience) que consiste em trazer as melhores práticas de código possíveis (e isso vai muito mais além do que escrever menos linhas como no exemplo) pra fazer com que um desenvolver que vá contribuir com seu código tenha a menor curva de aprendizado possível para que comece a ficar produtivo sozinho e se sinta confortável em alterar o código base da aplicação sem quebrar alguma funcionalidade e tenha a capacidade de escrever menos código entregando mais valor. Reflita sobre essas perguntas antes de começar a programar qualquer coia.
No próximo exemplo vamos entender bem o por que de eu ter citado sobre “Separation of Concerns” no começo do artigo, porém agora só com sagas:
No exemplo seguintes fazemos o seguinte:
- Um componente chama a action
@user/FETCH_REQUESTED - A nossa saga agora está “assistindo” qualquer execução dessa action e vai fazer a uma chamada para a api e, caso dê tudo certo, vai passar o usuário para outra action
- E essa outra action finalmente vai adicionar nosso usuário no nosso reducer
- Por fim, nosso reducer vai decidir o que vai fazer com o novo usuário, nesse caso adicionando em uma lista
Perceba como cada função tem uma responsabilidade muito pequena e isso é muito importante para leitura e interpretação de um código (além de facilitar muito os testes unitários).
Existem muitas variáveis para escolher entre uma biblioteca e outra e não é fácil mesmo, mas acredito que a partir de hoje vou preferir sagas ao invés de thunks.
Caso queira ver exemplos de estrutura de pastas e algumas aplicações funcionando na prática usando sagas com React e React Native:
Enfim, além de tudo que comentei nesse artigo sobre algumas tecnologias bem específicas, pense assim: Você pode economizar dias/semanas/meses se tomar decisões certas e 90% das respostas de todas as perguntas de programação estão nas documentações, e você precisa ler mais.
As bibliotecas mais usadas em Javascript tem documentações muito bem estruturadas e objetivas, mas não adianta de nada se você não procurar ou só procurar pelo que você acha que precisa. Organize-se para ter tempo de ler mais e com calma antes de assumir que alguma solução não é o que você precisa ou que talvez seja mais do que o necessário. Segue a documentação do redux-saga:
Apesar do puxão de orelha, acredite que você possa sempre fazer mais e melhor! Tomar decisões inteligentes vai fazer com que você ganhe mais confiança e consequentemente vão confiar mais em você! Foque em resultados, estude, discuta e troque ideias com outros desenvolvedores, você não está sozinho nessa!
Existem várias comunidades no Slack e no Discord pra tudo! O link seguinte é uma em especial sobre React/Redux e aprendo muito com pessoas do mundo inteiro, vale a pena entrar! Se ainda não tem uma conta em algumas dessas plataformas, crie! É de graça!
Happy coding!