No desenvolvimento de software, existem vários padrões propostos para lidar com a injeção de dependência. Angular impõe o padrão de injeção do construtor, que usa o construtor para passar as dependências de uma classe como parâmetros do construtor.

O Angular tem sua própria estrutura integrada de injeção de dependência (DI) que fornece dependências para classes na instanciação. Este é um recurso importante para construir aplicativos da web escalonáveis ​​no Angular.

Neste tutorial, mostraremos como a injeção de dependência funciona no Angular, percorrendo alguns exemplos práticos. Também revisaremos algumas práticas recomendadas e abordaremos algumas abordagens diferentes para lidar com a injeção de dependência em um aplicativo Angular.

Para acompanhar, você deve ter o seguinte:

  • Node.js V10.x
  • Conhecimento prévio de trabalho do Angular
  • Conhecimento prévio de trabalho em TypeScript

O que é injeção de dependência no Angular?

De acordo com a documentação oficial do Angular , injeção de dependência é “um padrão de design no qual uma classe solicita dependências de fontes externas, em vez de do que criá-los. ”

Resumindo, a injeção de dependência angular visa separar a implementação de serviços dos componentes. Isso facilita o teste, a substituição e a alteração dos serviços sem afetar os componentes dependentes desses serviços.

Na maioria das vezes, você encontrará alguns tutoriais ou bases de código angulares que tratam da injeção de dependência desta maneira:

 ng gerar produtos/produtos de serviço 

O comando acima cria um novo serviço Angular junto com outros arquivos que o acompanham.

//app/products/product.model.ts
interface de exportação do produto { número de identidade; nome: string;
}

O snippet acima usa a interface TypeScript para criar um modelo para validar os dados retornados do serviço de produtos.

//app/products/product.service.ts
importar {injetável} de'@ angular/core';
importar {Product} de'./product.model';
@Injectable ({ fornecido em:'root'
})
export class ProductService { construtor () {} getProducts (): Produto [] { Retorna [ {id: 1, nome:'Nike'}, {id: 2, nome:'Balenciaga'}, {id: 3, nome:'Gucci'}, {id: 4, nome:'Addidas'}, ]; }
}

A propriedade providedIn cria um provedor para o serviço. Nesse caso, providedIn:'root' especifica que o Angular deve fornecer o serviço no injetor raiz (ou seja, disponibilizá-lo em todo o aplicativo).

Agora, ProductService pode ser injetado em qualquer lugar em nosso aplicativo:

//app/products/product-list/product-list.component.ts
import {Component, OnInit} de'@ angular/core';
importar {Product} de'../product.model';
importar {ProductService} de'../product.service';
@Componente({ seletor:'app-product-list', templateUrl:'./product-list.component.html', styleUrls: ['./product-list.component.css'], provedores: [ProductService]
})
export class ProductListComponent implementa OnInit { produtos: Produto []; productService privado: ProductService; construtor () { this.productService=new ProductService (); } ngOnInit (): void { this.products=this.productService.getProducts (); }
}

O snippet acima instancia a propriedade privada productService usando a nova palavra-chave no construtor do componente, chama o método getProducts de productService dentro do ngOnInit e atribui o valor de retorno à propriedade products .

//app/products/product-list/product-list.component.html

Nossos produtos

  • (S/N: {{product.id}}) {{product.name}}

O snippet acima usa a diretiva ngFor para exibir a lista de produtos.

Se você executar o aplicativo usando o comando ng serve , tudo deve funcionar bem.

Embora tenhamos dissociado com sucesso nosso componente da lógica do produto por meio do serviço Angular, que é o principal objetivo do DI, essa abordagem ainda tem duas desvantagens principais. A primeira é que um novo serviço é criado cada vez que o ProductListComponent é renderizado. Isso pode impactar negativamente o desempenho do aplicativo em uma situação em que um serviço singleton é esperado.

Em segundo lugar, se alterarmos o construtor de ProductService para acomodar outra dependência, também precisaremos alterar a implementação do construtor ProductListComponent . Isso significa que o componente ainda está fortemente acoplado à implementação do serviço, o que pode tornar o teste do serviço muito difícil.

A prática recomendada para lidar com a injeção de dependência no Angular é a seguinte.

Atualize product-list.component.ts conforme mostrado abaixo:

//app/products/product-list/product-list.component.ts
...
export class ProductListComponent implementa OnInit { produtos: Produto []; construtor (productService privado: ProductService) {} ngOnInit (): void { this.products=this.productService.getProducts ();
}

Dessa forma, o componente não precisa saber como instanciar o serviço. Em vez disso, ele recebe a dependência e a injeta por meio de seu construtor. Essa abordagem torna mais fácil testar o serviço.

Como lidar com a injeção de dependência no Angular

Ao lidar com a injeção de dependência em um aplicativo Angular, você pode adotar uma abordagem baseada em aplicativo ou em componente. Vamos examinar as diferenças.

Injeção de dependência baseada em aplicativo

O framework Angular DI torna as dependências disponíveis em todo o aplicativo, fornecendo um injetor que mantém uma lista de todas as dependências do necessidades do aplicativo. Quando um componente ou serviço deseja usar uma dependência, o injetor primeiro verifica se já criou uma instância dessa dependência. Caso contrário, ele cria uma nova, a retorna ao componente e reserva uma cópia para uso posterior, de modo que da próxima vez que a mesma dependência for solicitada, ele retorne a dependência reservada em vez de criar uma nova.

Existem hierarquias associadas a injetores em um aplicativo Angular. Sempre que um componente Angular define um token em seu construtor, o injetor procura um tipo que corresponda a esse token no pool de provedores registrados. Se nenhuma correspondência for encontrada, ele delega a pesquisa no provedor do componente pai por meio da árvore injetora de componente. Se encontrar a dependência, ele para e retorna uma instância dela para o componente que a solicitou.

Se a pesquisa do provedor terminar sem correspondência, ele retorna ao injetor do componente que solicitou o provedor e pesquisa através dos injetores de todos os módulos pai na hierarquia do injetor do módulo até atingir o injetor raiz. Se nenhuma correspondência for encontrada, o Angular lançará uma exceção. Caso contrário, ele retorna uma instância da dependência do componente.

Já examinamos alguns trechos de código práticos para essa abordagem. Sinta-se à vontade para consultar a seção anterior se desejar revisá-la.

Injeção de dependência baseada em componente

Esta abordagem é conhecida por injetar as dependências diretamente na árvore de componentes usando a propriedade @Component do decorador Provedores para registrar serviços com um injetor de componente. Essa abordagem é comumente usada em aplicativos angulares.

Ao compartilhar dependências entre componentes filhos, as dependências são compartilhadas entre todos os componentes filhos do componente que fornece as dependências. Eles estão prontamente disponíveis para injeção nos construtores dos componentes filhos, fazendo com que cada componente filho reutilize a mesma instância do serviço do componente pai.

Digamos que desejemos exibir uma lista de produtos adicionados recentemente. Obviamente, o modelo para exibir uma lista de produtos adicionados recentemente é o mesmo para exibir todos os produtos. Portanto, podemos compartilhar a dependência (serviço) de produtos entre os componentes ProductListComponent e RecentProductComponent .

Crie um novo componente chamado recent-products dentro do módulo products com o seguinte comando:

 ng gerar produtos de componentes/produtos recentes--module=produtos

Atualize recent-products.component.ts da seguinte maneira:

 import {Component, OnInit} de'@ angular/core';
importar {ProductService} de'../product.service';
importar {Product} de'../product.model';
@Componente({ seletor:'app-recent-products', templateUrl:'./recent-products.component.html', styleUrls: ['./recent-products.component.css']
})
export class RecentProductsComponent implementa OnInit { produtos: Produto []; construtor (productService privado: ProductService) {} ngOnInit (): void { this.products=this.productService.getHeroes (); }
}

Aqui, injetamos ProductService no construtor de RecentProductsComponent sem realmente fornecê-lo por meio da propriedade provider do @component decorator, como fizemos para ProductListComponent .

Como consideramos a propriedade provider ausente do decorador @component ? Sem isso, o RecentProductsComponent não saberá como criar uma instância de ProductService .

Atualize o modelo ProductListComponent da seguinte maneira:

//app/products/product-list/product-list.component.html

Nossos produtos

  • (S/N: {{product.id}}) {{product.name}}

Responderemos à pergunta anterior tornando o RecentProductComponent um filho direto do ProductListComponent , dando ao RecentProductComponent acesso a todas as dependências fornecidas por ProductListComponent .

Atualize recent-products.component.html da seguinte maneira:

//app/products/recent-products/recent-products.component.html

Produtos recentes

  • {{Nome do Produto}}

Aqui, aplicamos o tubo de fatia à instrução ngFor para exibir apenas os primeiros cinco produtos.

Ao executar o aplicativo com o comando ng serve , você deve ver uma lista de todos os produtos e produtos recentes renderizados no navegador.

Conclusão

Neste tutorial, estabelecemos uma compreensão básica da injeção de dependência angular. Vimos vários exemplos práticos para demonstrar como as dependências são compartilhadas entre os componentes filhos, bem como o aplicativo inteiro. Também revisamos algumas práticas recomendadas para implementar injeção de dependência em seu próximo aplicativo Angular.

A postagem Como funciona a injeção de dependência no Angular apareceu primeiro no LogRocket Blog .

Source link