Mais plusieurs personnes m'ont désabonné qu'il leur est difficile de comprendre DI et ses capacités dans Angular. Il n'y a pas tellement de documents sur Internet sur la façon d'utiliser efficacement DI, et pour de nombreux développeurs, cela revient à travailler avec des services mondiaux ou à transmettre des données globales de la racine de l'application aux composants.
Examinons plus en détail ce mécanisme dans Angular.
Connaissez-vous vos addictions?
Parfois, il n'est pas facile de comprendre le nombre de dépendances de votre code.
Par exemple, jetez un œil à cette pseudo-classe et comptez le nombre de dépendances dont elle dispose:
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);
}
}
Répondre
fetch — API, , , .
API_URL — ( ).
new Logger() — , .
document — API .
API_URL — ( ).
new Logger() — , .
document — API .
Alors, qu'est-ce qui ne va pas?
Par exemple, une telle classe est difficile à tester car elle dépend des données importées à partir d'autres fichiers et des entités spécifiques qu'ils contiennent.
Autre situation: document et récupération fonctionneront de manière transparente dans votre navigateur. Mais si un jour vous devez transférer l'application vers Server Side Rendering, les variables globales nécessaires peuvent ne pas se trouver dans l'environnement nodejs.
Alors, qu'est-ce que DI et pourquoi est-il nécessaire?
L'injection de dépendances gère les dépendances au sein d'une application. En gros, pour nous, comme pour les développeurs Angular, ce système est assez simple. Il y a deux opérations principales: mettre quelque chose dans l'arborescence de dépendances ou en extraire quelque chose.
Pour une perspective plus théorique sur l'ID, lisez à propos de l'inversion du principe de contrôle . Vous pouvez également regarder des vidéos intéressantes sur le sujet: une série de vidéos sur l'IoC et la DI d'Ilya Klimov en russe ou une courte vidéo sur l'IoC en anglais.
Toute magie vient de l'ordre dans lequel nous fournissons et prenons les dépendances.
Comment fonctionnent les scopes dans DI:
Que pouvons-nous mettre en DI?
La première des opérations DI consiste à y mettre quelque chose. En fait, pour cela, Angular nous permet d'écrire le tableau des fournisseurs dans les décorateurs de nos modules, composants ou directives. Voyons en quoi ce tableau peut consister.
Fournir la classe
Habituellement, tous les développeurs Angular le savent. C'est le cas lorsque vous ajoutez un service à une application.
Angular crée une instance de la classe lorsque vous la demandez pour la première fois. Et avec Angular 6, nous ne pouvons pas du tout écrire de classes dans le tableau des fournisseurs, mais dire à la classe elle-même où dans la DI elle doit aller avec providedIn :
providers: [
{
provide: SomeService,
useClass: SomeService
},
// Angular :
SomeService
]
Fournir des valeurs
Des valeurs constantes peuvent également être fournies via DI. Il peut s'agir soit d'une simple chaîne avec l'URL de votre API, soit d'un observable complexe avec des données.
La fourniture de valeurs est généralement implémentée en conjonction avec un InjectionToken . Cet objet est la clé du moteur DI. Tout d'abord, vous dites: "Je veux obtenir ces données pour cette clé." Et plus tard, vous venez à DI et demandez: "Y a-t-il quelque chose sur cette clé?"
Eh bien, un cas courant est la transmission de données globales à partir de la racine de l'application.
Mieux vaut voir cela en action tout de suite, alors jetons un coup d'œil à stackblitz avec un exemple:
Développer l'exemple
Ainsi, dans l'exemple, nous avons obtenu la dépendance de DI au lieu de l'importer en tant que constante depuis un autre fichier directement. Et pourquoi est-ce mieux pour nous?
- Nous pouvons remplacer la valeur du jeton à n'importe quel niveau de l'arborescence DI sans changer les composants qui l'utilisent.
- Nous pouvons nous moquer de la valeur du jeton avec les données appropriées lors des tests.
- Le composant est complètement isolé et fonctionnera toujours de la même manière quel que soit le contexte.
Fournir des usines
À mon avis, c'est l'outil le plus puissant du moteur d'injection de dépendance d'Angular.
Vous pouvez créer un jeton qui sera le résultat de la combinaison et de la conversion des valeurs d'autres jetons.
Voici un autre stackbitz avec un exemple détaillé de création d'une usine avec un flux.
Développer l'exemple
Vous pouvez trouver de nombreux cas où la fourniture d'une usine permet de gagner du temps ou de rendre le code plus lisible. Parfois, nous injectons des dépendances dans des composants juste pour les combiner ou les transformer dans un format complètement différent. Dans l'article précédent, j'ai examiné cette question plus en détail et montré une approche alternative pour résoudre de telles situations.
Fournir une instance existante
Ce n'est pas un cas courant, mais cette option peut être un outil très utile.
Vous pouvez placer une entité qui a déjà été créée dans le jeton. Fonctionne bien avec forwardRef .
Regardez un autre exemple avec stackblitz avec une directive qui implémente l'interface et remplace un autre jeton par useExisting. Dans cet exemple, nous voulons remplacer la valeur de jeton DI uniquement pour les composants enfants de l'élément sur lequel la directive se bloque. De plus, la directive peut être n'importe laquelle - l'essentiel est qu'elle implémente l'interface requise.
Développer l'exemple
Astuces de décorateur DI
Les décorateurs DI vous permettent de rendre les requêtes DI plus flexibles.
Si vous ne connaissez pas les quatre décorateurs, je vous conseille de lire cet article sur Medium . L'article est en anglais, mais il existe des visualisations très intéressantes et compréhensibles sur le sujet.
Peu de gens savent également que les décorateurs DI peuvent être utilisés dans le tableau deps, qui prépare les arguments pour l'usine des fournisseurs.
providers: [
{
provide: SOME_TOKEN,
/**
* ,
* [new Decorator(), new Decorator(),..., TOKEN]
* .
*
* ‘null’,
* OPTIONAL_TOKEN
*/
deps: [[new Optional(), OPTIONAL_TOKEN]],
useFactory: someTokenFactory
}
]
Usine de jetons
Le constructeur InjectionToken prend deux arguments.
Le deuxième argument est un objet avec une configuration de jeton.
Une fabrique de jetons est une fonction appelée au moment où quelqu'un demande ce jeton pour la première fois. Dans celui-ci, vous pouvez calculer une certaine valeur standard pour le jeton ou même accéder à d'autres entités DI via la fonction inject.
Jetez un coup d'œil à un exemple de mise en œuvre de la fonctionnalité de flux de clics de bouton, mais cette fois à l'usine de jetons.
Développer l'exemple
Conclusion
DI in Angular est un sujet étonnant: à première vue, il n'y a pas beaucoup de leviers et d'outils différents à apprendre, mais vous pouvez écrire et parler pendant des heures des possibilités et des utilisations qu'ils nous donnent.
J'espère que cet article vous a donné les bases sur lesquelles vous pouvez trouver vos propres solutions pour simplifier le travail avec les données dans vos applications et bibliothèques.