Entendendo NgRx - Avanade Angular Projeto API - Weather
- #Angular
- #Redux
- #TypeScript
Programar com Angular tem sido muito proveitoso e prático, mas também um grande desafio. Conceitos como o de módulos, Observables e outros dão um verdadeiro nó na cabeça. E quando comecei a desenvolver o projeto da api-weather, ministrada pelo instrutor João Victor Ghignatti, percebi o poder que este framework traz, mas também o nível de conhecimento e prática que ele exige.
O que quero compartilhar com vocês hoje é sobre o que aprendi sobre o ngrx e como gerenciamento de estado pode ajudar ao criarmos aplicações escaláveis. Antes, quero ressaltar que ainda estou digerindo os conceitos (literalmente precisei construir o app 4 vezes para entender), e se você, caro leitor perceber algo de errado, sinta-se a vontade para comentar. Vamos lá!
Projeto: Site em Angular para consulta da previsão do tempo via API (openweather)
Nesse projeto fomos introduzidos ao NgRx, o redux do angular. O conceito é simples:
Digamos que na sua aplicação angular, você tenha 2 componentes, A e B respectivamente. E esses 2 componentes utilizem a mesma informação, que chamaremos de "I" (grande criatividade Samuel).
Em um momento, B decide fazer alterações em I, tornando ele um "IL". Assim, B alterou o estado, a forma da informação inicial, mas para A, I continuou a mesma coisa. "A" não sabe das mudanças de I e assim, sua visão da informação fica atrasada.
Aqui temos apenas 2 componentes, mas no mundo real uma aplicação pode ter literalmente dezenas de componentes que escutam e alteram informações. Assim, é necessário um sistema de gerenciamento de estado que em termos simples seria algo como: "Se B altera o componente "I" para "IL", quando A for visualizar a informação, ele encontrará "IL", e não "I".
Assim chegamos no Ngrx. Segundo a definição no próprio site, é um framework para construção de aplicações reativas em Angular. No nosso exemplo citado, o componente B "avisa" que deseja mudar a informação "I" e passa o novo valor "IL". A informação está guardada na Store, uma caixa grandona que guarda as informações. A Store recebe o aviso de B, junto com as novas informações e faz o processo para modificar a informação para "IL". Agora, para pegar a nova informação, B precisa pedir, ou "selecionar" a informação nova. Dessa forma, mesmo que não seja "B" que altere a informação, ele sempre será atualizado com a informação mais recente.
Passando pro código, temos as Actions, Reducers e Selectors e Effects, que são apresentados no projeto. O professor cita, que uma boa prática é sempre comecar pelas actions. No nosso projeto fictício, o componente B possui um input que registra a nova informação vinda do usuário, que deverá alterar a que está registrada na Store; e o componente A é responsável por mostrar na tela essa informação. Note que os 2 componentes interagem com a mesma informação. Assim é importante ter um gerenciamento de estado na aplicação. No nosso componente B temos algo como:
informacaoComponenteB.component).ts
alterarInformacao(){
const informacao = "Texto Novo";
this.store.dispatch(acoesDoComponenteB.enviarNovaInformacao({ informacao }));
}
O comando this.store.dispatch (store:Store é importada no construtor) é o responsável por passar o "aviso" da nova informação. Veja que o método recebe um parâmetro que é a nossa nova informação.
A nossa action seria definida da seguinte forma:
informacao.actions.ts
export const enviarNovaInformacao = createAction(
' [Componente B] Enviar Nova Informação ',
props <{ informacao:string }>()
)
A primeira parte do método é um rótulo informativo onde você vê quem dispara a action e o que ela tem q fazer (deixarei o link da extensão de desenvolvimento para visualização do estado no fim). A segunda parte é responsável por definir o que essa action precisa para funcionar, no caso uma informação do tipo string.
Quando ela é disparada, nossos reducers são avisados e tratarão de atualizar a informação com base nas regras definidas:
informacao.reducers
import * as todasAsActions from 'componentB.actions.ts';
export interface EstadoDaInformacao{
informacao:string;
}
export const estadoInicialDaInformacao: EstadoDaInformacao ={
informacao:' ';
}
const reducer = createReducer(
estadoInicialDaInformacao,
on(todasAsActions.enviarNovaInformacao, (state, { informacao }) =>({
...state,
informacao,
})),
);
export function homeReducer (state:EstadoDaInformacao|undefined, action:Action):EstadoDaInformacao{
return reducer(state, action)
}
Eu sei, a primeira vez que vi isso eu literalmente travei, e precisei ver mais 4 vezes pra comecar a entender (sério, não desista!), mas vamos lá:
Primeiro, defina o estado inicial da sua informação, o que ela precisa para ser definida, no nosso caso, uma informação do tipo string;
Defina o estado inicial da sua informacao, a cara que ela vai ter logo no inicio, pode ser um texto vazio como no nosso exemplo;
Crie o reducer: ele precisa de um estado inicial (que voce acabou de definir) e da acao que ele irá reagir (programacao reativa rules). Perceba que nesse momento ele pega aquela primeira informacao que voce passou la no componente, sacou? Com um estado e essa informacao, ele retorna um novo estado e vualá, a informacao foi alterada para todos que querem ver.
No final, crie uma funcao funcional que irá abstrair o comportamento e irá funcionar todas as vezes.
Já peço perdão pelo longo artigo, mas se ficou até aqui, você pode estar com algumas dúvidas:
- Como o componente A pega a nova informação?
- Posso receber informação de outros locais sem ser do usuário, como uma api ou backend?
- Como faço o setup inicial?
Irei criar a parte 2 desse artigo e espero publicá-la em breve, pois faltaram diversos outros conceitos como estrutura de diretórios, nomenclaturas e etc. E já peço 2 coisas:
Deixem sugestões de configurações, dicas, melhorias e por favor, se virem algum erro sintam-se à vontade para apontá-los;
E comente o que achou deste artigo, se ele te ajudou ou não, espero que sim kkkk.
Ah, e sobre a imagem no início do artigo: Como eu disse, tive dificuldades para realizar o projeto. Então decidi criá-lo do zero, apenas com html simples para entender data-bindings, comunicacao dos componentes e outras coisas. A prática leva a perfeição!
E entendo como pode ser difícil entender todos estes conceitos no início, mas novamente, não desista DEV!
Comente aqui se deseja um artigo explicando a configuração Inicial do NgRx!
Links:
Redux DevTools para chrome:
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=pt-BR
Site do NgRx:
https://ngrx.io/
Meu linkedin (me chama lá):
www.linkedin.com/in/samuel-ferreira-da-costa-025b72199