Introdução
O gerenciamento de estado é um aspecto crucial no desenvolvimento de aplicações web modernas, garantindo que os dados e as condições da aplicação sejam controlados e mantidos de forma organizada, escalável e eficiente. O Angular oferece diversas abordagens para lidar com o gerenciamento de estado, cada uma com suas vantagens e desvantagens. Entre as opções mais recentes e promissoras, destaca-se os Signals, introduzidos na versão 17 do framework.
O que é Estado?
Estado no Desenvolvimento de Software é uma representação de como os dados ou condições estão em um determinado momento. À medida que uma aplicação interage com o usuário ou processa informações, os estados podem mudar.
Esse gerenciamento permite que os dados sejam armazenados e atualizados garantindo a consistência entre os diferentes elementos da aplicação. Quando o gerenciamento de estado é feito da forma correta facilita escalar a aplicação, sua manutenibilidade e também melhorar a performance.
Abaixo podemos ver um exemplo ver como funciona a alteração de estado. Quando uma notificação chega para o usuário a quantidade exibida no ícone Sininho Azul é incrementada, e quando o status é alterado, podemos ver que ele passa de INATIVO para ATIVO.
O que são Signals?
Introduzido originalmente na Versão 17 do Angular, os Signals são uma forma revolucionária de criar aplicações reativas, baseadas em programação de fluxo de dados e propagação automática de mudanças. Os Signals fornecem uma maneira fácil e eficiente de relatar alterações de dados à estrutura da aplicação, permitindo otimizar a detecção de alterações e novas renderizações.
Vantagens dos Signals
Com os Signals, o Angular consegue saber exatamente qual parte da aplicação (componente) precisa ser atualizado, e irá atualizar somente essa parte, nada mais. Algumas de suas vantagens:
- Gerenciamento de Estado Simplificado: Fornecem uma maneira simples e elegante de gerenciar estado em aplicações Angular, tornando mais fácil lidar com mudanças de estado complexas
- Atualizações em Tempo Real: Permitem atualizações em tempo real do estado da aplicação, tornando-o ideal para aplicações que requerem feedback imediato
- Desacoplamento de Componentes: Ajudam a desacoplar componentes uns dos outros, tornando mais fácil desenvolver e manter aplicações em larga escala
- Melhoria no Desempenho: Podem melhorar o desempenho reduzindo o número de cálculos e atualizações desnecessárias
- Depuração Fácil: Fornecem uma maneira clara e concisa de depurar mudanças de estado, tornando mais fácil identificar e corrigir problemas
- Flexibilidade e Customização: Podem ser customizados para atender a casos de uso específicos, fornecendo um alto grau de flexibilidade e customização
- Escalabilidade: Sinais são projetados para escalar com aplicações grandes e complexas, tornando-os uma escolha ideal para desenvolvimento em larga escala
- Legibilidade de Código Melhorada: Promovem um estilo de codificação mais declarativo, tornando mais fácil ler e entender o código
Desvantagens dos Signals
Os Signals são uma ferramenta poderosa para gerenciamento de estado no Angular, mas como qualquer outra tecnologia, eles também têm seus pontos negativos aqui estão algumas das desvantagens de usar signals:
- Curva de aprendizado mais acentuada: São um conceito relativamente novo no Angular e requerem um bom entendimento de RxJS e Observables. Isso pode tornar o aprendizado e o domínio de novos desenvolvedores um desafio
- Over-Engineering: Podem levar ao over-engineering de estado do aplicativo, dificultando a manutenção e a depuração. Com grande poder vem grandes responsabilidades e é essencial usar os signals criteriosamente
- Suporte limitado para programação imperativa: Projetados para funcionar com programação reativa, o que pode dificultar a integração com estilos de programação imperativa
- Suporte limitado para navegadores legados: Dependem de recursos modernos de JavaScript, o que pode tornar um desafio o suporte a navegadores legados
- Complexidade no tratamento de erros: Os sinais podem tornar o tratamento de erros mais complexo devido à natureza assíncrona dos sinais. Isso pode levar a dificuldades na identificação e tratamento de erros
Sabendo dessas desvantagens, os desenvolvedores podem decidir quando usar Signals e como contornar seus limites.
Características dos Signals
Além disso, os Signals têm algumas características importantes:
- Podem conter qualquer valor, desde primitivos simples até estruturas de dados complexas como, Models, Types e Interfaces
- São observáveis, o que significa que os componentes podem se inscrever em mudanças nos valores dos Signals
- São imutáveis, o que significa que os valores dos Signals não podem ser alterados diretamente
Gerenciamento de Estado
O gerenciamento de estado é um desafio comum em aplicações web complexas. No Angular, existem várias formas de gerenciar o estado da aplicação, cada uma com suas próprias vantagens e desvantagens.
O que é Gerenciamento de Estado?
O gerenciamento de estado se refere ao processo de armazenar, atualizar e recuperar os dados da aplicação. O estado da aplicação pode incluir informações como o usuário logado, dados do formulário, resultados da API, entre outros.
Importância do Gerenciamento de Estado
O gerenciamento de estado é importante porque:
- Melhora a experiência do usuário: Ao armazenar o estado da aplicação, você pode proporcionar uma experiência mais consistente e previsível para os usuários
- Facilita o desenvolvimento: O gerenciamento de estado pode ajudar a simplificar o código e a reduzir a complexidade da aplicação
- Aumenta a escalabilidade: Ao separar o estado da aplicação em diferentes componentes, você pode facilmente adicionar ou remover recursos sem afetar a estabilidade da aplicação
Formas de Gerenciamento de Estado no Angular
Existem várias formas de gerenciar o estado da aplicação no Angular, incluindo:
- Services: São singletons que podem ser injetados em componentes para fornecer acesso a dados e funcionalidades compartilhadas
- Component State: O estado de um componente pode ser gerenciado utilizando propriedades e métodos do próprio componente
- Redux e NgRx: Redux e NgRx são bibliotecas de gerenciamento de estado que podem ser utilizadas com o Angular
- Local Storage e Session Storage: O local storage e o session storage são formas de armazenar dados no lado do cliente
- Signals: S são uma forma de gerenciar o estado da aplicação em Angular, introduzida na versão 17
Desafios do Gerenciamento de Estado
O gerenciamento de estado também apresenta alguns desafios, como:
- Complexidade: O gerenciamento de estado pode ser complexo, especialmente em aplicações grandes e escaláveis
- Consistência: É importante garantir que o estado da aplicação seja consistente e atualizado em todos os lugares
- Segurança: O gerenciamento de estado também pode apresentar riscos de segurança, como a exposição de dados sensíveis
Estratégias de Detecção de Mudanças
Os componentes aceitam uma configuração de detecção de alterações, o changeDetection, que controla o modo de detecção de alterações do componente. Existem duas opções de modo de detecção de alterações, o ChangeDetectionStrategy.Default e o ChangeDetectionStrategy.OnPush.
O ChangeDetectionStrategy.Default é o modo padrão usado pelo nos componentes, com ele o Angular verifica se o DOM do componente precisa de uma atualização sempre que alguma atividade pode ter ocorrido em todo o aplicativo, marca todos os componentes como dirty, ou seja, marca como se todos os componentes tivessem tido alterações, e assim renderiza os componentes novamente. Atividades que podem desencadear essa verificação incluem interação do usuário, resposta de rede, temporizadores, etc.
No GIF abaixo temos o funcionamento do modo default, onde temos um incremento automático no contador do componente de número 13 (último no canto inferior direito), a cada segundo. Neste exemplo estamos usando o BehaviorSubject do RXJS para gerenciar o estado do componente.
Como podemos notar, todos os componentes estão atualizando a cada atualização/incremento do componente 13.
O ChangeDetectionStrategy.OnPush é opcional e reduz a quantidade de verificações que o Angular precisa executar. Neste modo o framework verifica apenas se o DOM do componente precisa de atualização quando:
- O input de um componente sofre alterações, seja por uma ação do usuário ou outra fonte de dados
- Um event listener nesse componente é executado
- O componente é explicitamente marcado para verificação, via markForCheck ou algo que o envolva como um AsyncPipe
Quando um componente OnPush é verificado, o Angular verifica apenas os seus componentes ancestrais, percorrendo a árvore de componentes acima, e não os componentes de toda a aplica como no exemplo anterior.
No GIF abaixo temos o funcionamento do modo OnPush, como no exemplo anterior temos um incremento automático no contador do componente de número 13, a cada segundo, utilizando também o BehaviorSubject do RXJS.
Como podemos notar, somente os componentes ancestrais ao componente 13 estão atualizando a cada atualização/incremento.
E por fim, podemos ver abaixo o mesmo exemplo utilizando o Signal, ao invés do BehaviorSubject. Apenas no componente 13 está detectando alterações, o Angular faz a checagem dos componentes ancestrais 1, 3 e 7, mas marca somente o componente 13 para atualizações.
Implementando o Gerenciamento de Estado com Signals
O Angular Signals acompanham de forma detalhada como e onde seu estado é utilizado em toda a aplicação, permitindo que o framework otimize as atualizações de renderização. Algumas vantagens de se utilizar os signals no gerenciamento de estado incluem:
- Ganho de Performance: As aplicações podem se beneficiar de um desempenho melhorado
- Simplicidade nas Aplicações: A “reatividade leve” dos signals pode simplificar o desenvolvimento
- Experiência do Desenvolvedor Aprimorada: Os desenvolvedores podem desfrutar de uma experiência mais agradável ao trabalhar com signals
Vamos ver como podemos definir e utilizar os Signals em nossos códigos com alguns exemplos. Um exemplo implementando signals deve ser algo parecido com as imagens abaixo. Onde estamos criando dois Signals, um para a quantidade de notificações, e outro para o status.
É importante notar que podemos usar a tipagem que desejamos, seja ela do tipo primitiva (Status – Boolean) ou um tipo mais complexo (Notificações – Notification[]). Sempre devemos inicializar um signal com um valor, independentemente do valor que seja.
Função Set
Aqui estamos definindo (setando) um valor, utilizando o método set. Chamamos nossa variável e acessamos o método passando o valor que desejamos inserir. Estamos adicionando um array vazio nas notificações e deixando o status como true, dessa forma seus dependentes serão notificados.
Função Update
Para atualizar um signal, devemos utilizar o método update. O update atualiza o signal baseado no seu valor atual. Utilizamos uma arrow function que fornece o valor atual da variável, permitindo atualizar como for necessário, retornando um valor somente leitura.
Função Computed
Às vezes, precisamos fazer tratativas com as variáveis, então definimos um Computed Signal. Por exemplo, pra calcular a quantidade de notificações. Na linha 1 estamos acessando o array de notificações e com o length obtemos o tamanho desse array. O Computed Signal é de apenas leitura; ele não pode ser modificado usando os métodos set e update. Seu valor é “recomputado” quando um ou mais signals dependentes são alterados e o valor do computed signal é lido.
Lendo Signals
E como podemos acessar o valor de um Signal? Diferentemente das variáveis que já conhecemos, os signals são funções que retornam o valor atual. Para acessar seu valor devemos chamá-los como funções meuSignal()
.
Conclusão
O gerenciamento de estados no Angular é uma parte crucial do desenvolvimento de aplicações web modernas. Com a introdução dos Signals, o Angular oferece uma forma eficiente e escalável de lidar com o gerenciamento de estados, proporcionando uma melhor experiência tanto para os desenvolvedores quanto para os usuários finais. Ao compreender as vantagens e desvantagens dos Signals, os desenvolvedores podem tomar decisões bem fundamentadas sobre quando e como utilizá-los em suas aplicações, o que assegura um desenvolvimento mais eficaz e uma experiência de usuário mais satisfatória.
Live Preview StackBlitz
Referências
- Neto C. Alvaro (2024). Angular Design Patterns and Best Practives. Editora Packt Publishing Ltd.
- Signals • Overview • Angular
- Application State Management with Angular Signals | by 🪄 OZ 🎩 | Medium
- Manage State with Angular Signals (youtube.com)
- 📜State Management Using Signal in Angular | by Tacettin Sertkaya | Medium
- O que é gerenciamento de estado em aplicações web? (dio.me)
- Gerenciando estado no Angular (dio.me)
- Gerenciamento De Estado No Front End: Tudo O Que Você Precisa Saber
- Angular State Management: A Comparison of the Different Options Available – DEV Community
- Managing State in Angular with ngrx/store | by Sumit kumar Singh | Medium
- Angular Signals: Complete Guide (angular-university.io)]
- Signals Unleashed: The Full Guide – YouTube