我要问自己,上级/下级组件中的@Input
/ @Output
和使用使用仅通过依赖关系注入实例化的服务{{1} }}。或者,除了“输入/输出”只能在parent- / child-comp中使用之外,还有其他区别。
以下示例可提供更好的可视化效果:
@Injectable()
ChildComponent:
<parent-comp>
<child-comp [inputFromParent]="valueFromParent"></child-comp>
</parent-comp>
@Component({
selector: 'child-comp',
template: ...
})
export class ChildComponent {
@Input() public inputFromParent: string;
}
现在,我们可以在父组件中设置值。并通过依赖注入获得子代的价值。 ChildComponent:
@Injectable()
export class Service {
private value: string;
public get value(): string {
return value;
}
public set value(input): void {
value = input;
}
}
尽管第一种方法看起来更简单,但我认识到通过父子组件使用了3-4个属性carriyng。与@Component({
selector: 'child-comp',
template: ...
})
export class ChildComponent {
private value: string;
constructor(private service: Service) {
this.value = this.service.getValue;
}
}
/ @Input
配合使用时,棉塞非常混乱且笨拙。
答案 0 :(得分:6)
这不是一个具有明确答案的问题,但是...
@Input
和@Output
在父母与子女之间的交流仅仅是父母与子女之间的交流时很有用。拥有一个仅维护两个组件的单例数据的服务就没有任何意义(或者深嵌套的祖父母->父->子组件)。
如果您的父母需要对孩子的变化做出反应,它们也很有用。例如,单击子组件中的一个按钮,该按钮在父组件中调用一个函数:
<my-child-component (myOutputEmitter)="reactToChildChange($event)"></my-child-component>
在父级中:
reactToChildChange(data: any) {
// do something with data
}
如果您发现自己将许多@Input
属性传递给孩子,并且想要整理一个模板,则可以为输入定义一个接口,然后将其传递。例如
export interface MyChildProperties {
property?: any;
anotherProperty?: any;
andAnotherProperty?: any;
}
然后,您可以将定义传递给您的孩子,该定义由父级设置:
childProperties: MyChildProperties = {
property: 'foo',
anotherProperty: 'bar',
andAnotherProperty: 'zoob'
}
那么您的子组件可能具有:
@Input properties: MyChildProperties;
您的模板变为:
<my-child-component [properties]="childProperties"></my-child-component>
您的孩子可以从properties.property
,properties.anotherProperty
等访问这些属性。
干净,整洁,您的数据现在包含在需要通信的那些组件中。
但是,应该在一个以上组件需要访问整个应用程序中的读/写数据的地方使用服务。例如,考虑一个UserService
,其中许多不同的组件需要能够访问当前登录的用户。在这种情况下,服务是明智的,因为它是单例的,因此一旦您设置了登录用户,注入UserService
的任何组件都可以访问其数据和功能。
类似地,如果您要使用服务来对更改做出反应,那么您会发现自己使用可观察对象编写服务,以便您的组件可以订阅数据中的更改。如上所述,事件发射器已经使用@Output
为您提供了这种模式。
如果它是简单的父级->子级通信,则这是不必要的开销,应该避免。
也就是说,如果您发现自己使用服务来管理全局状态,那么最好使用某种形式的状态管理,例如ngrx