O que pode ser colocado no mecanismo de injeção de dependência no Angular?

Quase todo desenvolvedor Angular pode encontrar uma solução para seu problema na injeção de dependência. Isso foi visto claramente nos comentários do meu último artigo . As pessoas consideraram várias opções para trabalhar com os dados do DI, comparando sua conveniência para uma situação particular. É ótimo porque uma ferramenta tão simples nos oferece muitas possibilidades.



Mas várias pessoas cancelaram minha assinatura dizendo que é difícil para elas entender o DI e seus recursos no Angular. Não há tantos materiais na Internet sobre como usar o DI com eficácia e, para muitos desenvolvedores, isso se resume a trabalhar com serviços globais ou passar dados globais da raiz do aplicativo aos componentes.



Vamos dar uma olhada mais profunda neste mecanismo no Angular.









Você conhece seus vícios?



Às vezes, não é fácil entender quantas dependências seu código possui.



Por exemplo, dê uma olhada nesta pseudoclasse e conte quantas dependências ela tem:



import { API_URL } from '../../../env/api-url';
import { Logger } from '../../services/logger';
 
class PseudoClass {
   request() {
       fetch(API_URL).then(...);
   }
 
   onError(error) {
       const logger = new Logger();
 
       logger.log(document.location, error);
   }
}


Responda
fetch — API, , , .



API_URL — ( ).



new Logger() — , .



document — API .





Então, oque há de errado?



Por exemplo, essa classe é difícil de testar porque depende de dados importados de outros arquivos e entidades específicas neles.



Outra situação: document e fetch funcionarão perfeitamente em seu navegador. Mas se um dia você precisar transferir o aplicativo para o Server Side Rendering, então as variáveis ​​globais necessárias podem não estar no ambiente nodejs.



Então, o que é DI e por que é necessário?



A injeção de dependência gerencia dependências dentro de um aplicativo. Basicamente, para nós, como para desenvolvedores Angular, este sistema é bastante simples. Existem duas operações principais: colocar algo na árvore de dependências ou obter algo dela.



Para uma perspectiva mais teórica sobre DI, leia sobre o Princípio de Inversão de Controle . Você também pode assistir a vídeos interessantes sobre o assunto: uma série de vídeos sobre IoC e DI de Ilya Klimov em russo ou um pequeno vídeo sobre IoC em inglês.



Toda mágica vem da ordem em que fornecemos e assumimos dependências.



Como escopos funcionam em DI:





O que podemos colocar em DI?



A primeira das operações DI é colocar algo nela. Na verdade, para isso, o Angular nos permite escrever o array de fornecedores nos decoradores de nossos módulos, componentes ou diretivas. Vamos ver no que esse array pode consistir.



Ministrando aula



Normalmente, todo desenvolvedor Angular sabe disso. É quando você adiciona um serviço ao seu aplicativo.



Angular cria uma instância da classe quando você a solicita pela primeira vez. E com o Angular 6, não podemos escrever classes na matriz de provedores, mas dizer à própria classe onde na DI ela deve ir com providedIn :



providers: [
   {
       provide: SomeService,
       useClass: SomeService
   },
   // Angular        :
   SomeService
]




Fornecendo valores



Os valores constantes também podem ser fornecidos via DI. Pode ser uma string simples com o URL de sua API ou um Observable complexo com dados.



O fornecimento de valores geralmente é implementado em conjunto com um InjectionToken . Este objeto é a chave para o motor DI. Primeiro você diz: "Quero obter esses dados para esta chave." E depois você chega ao DI e pergunta: "Tem alguma coisa nessa chave?"



Bem, um caso comum é o encaminhamento de dados globais da raiz do aplicativo.



Melhor vê-lo em ação imediatamente, então vamos dar uma olhada no stackblitz com um exemplo:



Expandir exemplo






Portanto, no exemplo, obtivemos a dependência de DI em vez de importá-la como uma constante de outro arquivo diretamente. E por que é melhor para nós?



  • Podemos substituir o valor do token em qualquer nível na árvore DI sem alterar os componentes que o utilizam.
  • Podemos simular o valor do token com os dados apropriados durante o teste.
  • O componente é completamente isolado e sempre funcionará da mesma forma, independentemente do contexto.




Fornecimento de fábricas



Na minha opinião, esta é a ferramenta mais poderosa no mecanismo de injeção de dependência do Angular.



Você pode criar um token que será o resultado da combinação e conversão dos valores de outros tokens.



Aqui está outro stackbitz com um exemplo detalhado de criação de uma fábrica com um fluxo.



Expandir exemplo






Você pode encontrar muitos casos em que fornecer uma fábrica economiza tempo ou torna o código mais legível. Às vezes, injetamos dependências em componentes apenas para combiná-los ou transformá-los em um formato completamente diferente. No artigo anterior, examinei esse problema com mais detalhes e mostrei uma abordagem alternativa para resolver tais situações.



Fornecendo uma instância existente



Não é um caso comum, mas esta opção pode ser uma ferramenta muito útil.



Você pode colocar uma entidade que já foi criada no token. Funciona bem com forwardRef .



Veja outro exemplo stackblitz com uma diretiva que implementa a interface e substitui outro token por useExisting. Neste exemplo, queremos substituir o valor do token somente DI para os componentes filhos do elemento no qual a diretiva se pendura. Além disso, a diretiva pode ser qualquer - o principal é que ela implemente a interface necessária.



Expandir exemplo






DI Decorator Tricks



Os decoradores de DI permitem que você torne as consultas de DI mais flexíveis.



Se você não conhece os quatro decoradores, aconselho que leia este artigo no Medium . O artigo está em inglês, mas existem visualizações muito legais e compreensíveis sobre o assunto.



Muitas pessoas também não sabem que os decoradores de DI podem ser usados ​​no array deps, que prepara os argumentos para a fábrica de provedores.




providers: [
   {
     provide: SOME_TOKEN,
     /**
      *     ,  
      * [new Decorator(), new Decorator(),..., TOKEN]
      * .
      *
      *      ‘null’,     
      * OPTIONAL_TOKEN
      */
     deps: [[new Optional(), OPTIONAL_TOKEN]],
     useFactory: someTokenFactory
   }
 ]




Token Factory



O construtor InjectionToken aceita dois argumentos.



O segundo argumento é um objeto com uma configuração de token.



Uma fábrica de tokens é uma função que é chamada no momento em que alguém solicita esse token pela primeira vez. Nele, você pode calcular um determinado valor padrão para o token ou até mesmo acessar outras entidades DI através da função injetar.



Dê uma olhada em um exemplo de implementação da funcionalidade de fluxo de clique de botão, mas desta vez na fábrica de tokens.



Expandir exemplo






Conclusão



DI in Angular é um tópico incrível: à primeira vista, não tem muitas alavancas e ferramentas diferentes para aprender, mas você pode escrever e falar por horas sobre as possibilidades e os usos que eles nos dão.



Espero que este artigo tenha fornecido a base sobre a qual você pode criar suas próprias soluções para simplificar o trabalho com dados em seus aplicativos e bibliotecas.



All Articles