A equipe de desenvolvedores da Pris se dedica diariamente à evolução de nossos softwares, de forma a atender melhor nossos parceiros e clientes. Essa dedicação se dá tanto no aspecto de backend, quanto no de front end. Uma de nossas soluções, o Pris, utiliza o framework web Angular com bibliotecas adicionais para auxiliar o desenvolvimento, a manutenibilidade e a performance do nosso projeto. Uma dessas bibliotecas é o NgRx, responsável por controlar o estado da nossa aplicação de uma maneira estruturada e organizada.
Para alinharmos os conceitos iniciais, é importante explicar: o estado da aplicação é o conjunto de dados que afetam o que você vê na tela. Ao manter dados em componentes e dentro da árvore de componentes ao invés de usar essa estrutura, há uma consequência problemática: podem ser geradas longas cadeias de Inputs e Outputs entre componentes, que podem ser custosas para manutenção. Os dados podem começar a se tornar inconsistentes e a legibilidade do fluxo de dados pode ficar comprometida.
E o que o NgRx faz, junto ao Angular, para resolver esse problema? Ele basicamente controla os dados externamente a essa árvore de componentes e os distribui por meio de Observables.
Para explicar o que são Observables cabe uma analogia: imagine uma linha de transmissão telefônica. Quando alguém atende, a pessoa começa a escutar as palavras que são emitidas na linha. Essa linha de transmissão é o Observable. As palavras são os dados que ele emite. A pessoa é quem se inscreve na linha de transmissão para receber os dados, podendo ser uma componente, um serviço, entre outros.
A estrutura do NgRx é baseada na arquitetura do Redux e faz forte uso da biblioteca de programação assíncrona, RxJS.
Explicando de forma didática:
Os Effects são uma poderosa ferramenta para eliminar vazamento de responsabilidades das componentes.
De forma resumida, ele fica escutando as ações (Actions) emitidas até capturar a ação que ele irá lidar. Depois de lidar com as chamadas externas, ele emite uma nova ação (Action), geralmente, de sucesso ou de erro, de acordo com o resultado da chamada externa.
Sem Effects, dependendo da arquitetura do projeto, sua componente será responsável por:
Quanto mais responsabilidades suas componentes tiverem, mais difícil será a manutenção e a legibilidade do projeto.
Com Effects, sua componente irá apenas escutar os dados/erros vindo da Store. Quem efetivamente irá lidar com a API e com o erro ou o sucesso na requisição é o Effect.
API: createAction
Parâmetros:
API: createReducer
Importante: o Reducer não cria novos estados com o estado atual alterado. Ele constrói um novo estado da aplicação por meio de funções puras (pure functions¹), indo de encontro ao princípio da imutabilidade (immutability²).
Parâmetros:
API: createEffect
Parâmetros:
O NgRx oferece uma extensão à CLI do Angular para gerar seus recursos por meio dos schematics.
Os arquivos de Effects, Reducer, Store, Actions e Selectors podem não ser intuitivos para serem criados “à mão” e, graças aos Schematics, podemos gerá-los automaticamente.
O padrão para gerar esses recursos é o mesmo da CLI do Angular.
Para depurar nossa aplicação, utilizamos uma robusta extensão no navegador chamada Redux DevTools. Por meio da interface visual desse, é possível visualizar todo o estado da aplicação, as mudanças no estado da aplicação por Action e, também, navegar entre os estados anteriores da aplicação, graças à imutabilidade dos estados (immutability²).
Para usá-lo, basta adicionar o módulo nos imports do app.module:
API: StoreDevtoolsModule.instrument()
Parâmetros (opcional): https://ngrx.io/guide/store-devtools/config ( )
Se quiser trocar experiências e conhecimentos sobre Angular, NgRx ou outros temas de TI, basta entrar em contato! Será um prazer para toda a nossa equipe. E caso queira trabalhar conosco, siga nossa página de vagas clicando aqui.
¹pure functions: são funções que sempre quando recebem os mesmos argumentos, retornam a mesma coisa. Para o nosso caso, não podemos alterar nosso estado atual, já que pode acarretar em mudanças no retorno. Benefício: se elas sempre têm o mesmo retorno, elas podem utilizar resultados já calculados para economizar processamento.
²immutability: quando um objeto é criado, não podemos alterá-lo! Para alterá-lo, devemos copiá-lo e, depois, alterar a cópia. Benefício: detecção de mudança rápida (sem imutabilidade, o processamento de comparação deve comparar cada atributo do objeto).
Fonte das imagens:
Imagem 1 - Celestialsys
Imagem 2 - NgRx.io
Imagem 3 - Github