Je me demande où sont les différences entre @Input
/@Output
Dans les composants parents/enfants et en utilisant des services qui ne sont instanciés qu'une fois avec la dépendance Injection@Injectable()
. Ou y a-t-il des différences en plus des entrées/sorties ne peuvent être utilisées que dans les compositions parent/enfant.
Exemple suivant pour une meilleure visualisation:
<parent-comp>
<child-comp [inputFromParent]="valueFromParent"></child-comp>
</parent-comp>
ChildComponent:
@Component({
selector: 'child-comp',
template: ...
})
export class ChildComponent {
@Input() public inputFromParent: string;
}
@Injectable()
export class Service {
private value: string;
public get value(): string {
return value;
}
public set value(input): void {
value = input;
}
}
Maintenant, nous pouvons définir la valeur dans la composition parent. et obtenir la valeur dans la composition enfant avec injection de dépendance. ChildComponent:
@Component({
selector: 'child-comp',
template: ...
})
export class ChildComponent {
private value: string;
constructor(private service: Service) {
this.value = this.service.getValue;
}
}
Même si la première approche semble plus simple, j'ai reconnu l'utilisation de 3-4 propriétés carriyng via la composition parent/enfant. avec @Input
/@Output
rend le tamplete très déroutant et maladroit.
Pas exactement une question avec une réponse définie, mais ...
@Input
et @Output
sont utiles si la communication entre un parent et un enfant n'est que cela, entre un parent et un enfant. Il ne serait pas logique d'avoir un service qui conserve des données singleton pour seulement 2 composants (ou pour autant que les grands-parents profondément imbriqués -> parent -> composants enfants le soient).
Ils sont également utiles si votre parent doit réagir à un changement de l'enfant. Par exemple, en cliquant sur un bouton dans un composant enfant qui appelle une fonction dans le parent:
<my-child-component (myOutputEmitter)="reactToChildChange($event)"></my-child-component>
Et en parent:
reactToChildChange(data: any) {
// do something with data
}
Si vous passez plusieurs @Input
propriétés à un enfant et que vous souhaitez ranger un modèle, vous pouvez alors définir une interface pour l'entrée et la transmettre à la place. par exemple.
export interface MyChildProperties {
property?: any;
anotherProperty?: any;
andAnotherProperty?: any;
}
Ensuite, vous pouvez transmettre une définition à votre enfant, qui est définie à partir du parent:
childProperties: MyChildProperties = {
property: 'foo',
anotherProperty: 'bar',
andAnotherProperty: 'zoob'
}
Votre composant enfant peut alors avoir:
@Input properties: MyChildProperties;
et votre modèle devient:
<my-child-component [properties]="childProperties"></my-child-component>
Votre enfant peut accéder à ces propriétés à partir de properties.property
, properties.anotherProperty
, etc.
Nettoyez, rangez et vos données sont désormais contenues dans les composants qui doivent communiquer.
Cependant, les services doivent être utilisés lorsque plusieurs composants ont besoin d'accéder à des données en lecture/écriture sur l'ensemble de votre application. Considérez un UserService
par exemple, où de nombreux composants différents doivent pouvoir accéder à l'utilisateur actuellement connecté. Dans ce cas, un service est raisonnable, car c'est un singleton, donc une fois que vous avez défini votre utilisateur connecté, tous les composants qui injectent UserService
peuvent accéder à ses données et fonctions.
De même, si vous deviez utiliser un service pour réagir au changement, vous vous retrouveriez à écrire des services avec des observables afin que vos composants puissent s'abonner aux modifications des données. Les émetteurs d'événements vous donnent déjà ce modèle avec @Output
Comme montré ci-dessus.
S'il s'agissait d'une simple communication parent -> enfant, cela ne représente pas de frais généraux inutiles et devrait être évité.
Cela dit, si vous utilisez des services pour gérer l'état global, vous feriez mieux d'utiliser une forme de gestion d'état telle que ngrx