【问题标题】:Angular - Dependency injection through @Input propertyAngular - 通过@Input 属性进行依赖注入
【发布时间】:2020-10-24 07:07:55
【问题描述】:

@Input 属性中注入“服务”依赖项是一种好习惯吗?此上下文中的服务不是在根级别管理的单例实例,而是接口的不同实现的多个实例。

考虑以下示例:在 Angular 库中,ShapeComponent 依赖于 ShapeService(接口)。

组件

@Component({
  selector: 'ex-shape',
  templateUrl: '..',
})    

export class ShapeComponent {
   constructor(shapeServiceCtor: ShapeService)
    
   @Input shapeServiceInput: ShapeService;
}

解决依赖的一种简单方法是设置输入属性,如下代码所示。

<ex-shape [shapeServiceInput]="rectangleShapeService" />
<ex-shape [shapeServiceInput]="ellipseShapeService" />
<ex-shape [shapeServiceInput]="polygonShapeService" />

上述方法在解决组件中的依赖关系方面是否有效?

如果使用输入属性方法,则服务/依赖项必须以相同的方式传播到子组件。这种方法的缺点是父组件必须接受所有依赖项作为输入属性。

是否有任何推荐的方法来在库级别注入和作用域依赖项?

【问题讨论】:

    标签: angular typescript dependency-injection angular-dependency-injection


    【解决方案1】:

    这可能适用于您的情况:

    @Component({
      selector: 'ex-shape',
      templateUrl: '..',
    })    
    export class ShapeComponent {
       // change the type to any since any service will be comping as input
       private shapeServiceCtor: any;
    
       constructor(
           private injector: Injector // injector to inject incoming services
       ) {}
    
       // type as any
       @Input shapeServiceInput: any;
    
       ngOnInit() {
           // this will inject the service
           this.shapeServiceCtor = this.injector(shapeServiceInput);
       }
    }
    

    【讨论】:

      【解决方案2】:

      @Input 和@Output 用于通信,一个组件与另一个组件之间的通信。 @Input 会将我们的变量暴露给组件外部。依赖注入是一个不同的概念,在依赖注入中,我们在构造函数中注入组件和内置类,这将为我们提供。 @Input 绝对不是正确的方法。

      【讨论】:

        【解决方案3】:

        从@Injectable () 装饰器中移除参数。它确保不在根级别提供服务:

        @Injectable()
        export class ShapeService{
        

        您可以在组件级别声明服务,并且可以将服务照常注入任何子组件。子组件将获得与父组件相同的实例。

        在ShapeComponent中,可以在@Component装饰器中提供服务:

        @Component({
          selector: 'ex-shape',
          templateUrl: '..',
          providers:  [ ShapeService ]
        })    
        
        export class ShapeComponent {
           constructor(private shapeServiceCtor: ShapeService)
        

        这假设您希望每个 ShapeComponent 都有一个新的 ShapeService 实例。

        【讨论】:

          【解决方案4】:

          对于@Injectable 装饰器,您应该将providedIn 设置为true

          您的想法是使用单例,并且可以通过将providedIn 设置为true 来实现单例注入。

          那么你不需要深入使用@Input装饰器,你可以简单地导入服务并在你要使用的组件中使用它。

          所以格式应该是这样的。

          @Injectable({
              providedIn: true
          })
          export class SomeService {
           ...
          }
          

          【讨论】:

            【解决方案5】:

            “注入”这样的服务是行不通的。您将必须传递所述服务的实例。相反,尝试创建多个形状组件,如果它们共享功能,则让它们扩展基本组件或使用服务在它们之间共享。

            【讨论】:

              【解决方案6】:

              此时您并没有真正使用 Angular 的依赖注入,在您的情况下,我不确定这是好是坏。

              如果 ShapeComponent 无法知道它正在使用的服务实例,并且任何时候调用它都需要传递一个任意实例,这应该没问题。

              如果 ShapeComponent 的父级始终传递相同的服务实例,则父级可以将其包含在其 providers 数组中,然后子级 ShapeComponents 将使用相同的实例。

              Angular 的文档有一些关于 DI Hierarchy https://angular.io/guide/hierarchical-dependency-injection的更详细信息

              您对constructor(shapeServiceCtor: ShapeService) 的调用也会导致一些混乱,因为组件将同时注入一个DI,以及来自@Input 的另一个(或可能相同)实例

              【讨论】:

              • 包含构造函数参数以讨论替代方法,最终将遵循构造函数或输入依赖项。如果使用输入属性方法,则服务必须以相同的方式传播到子组件。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-08-13
              • 2021-02-26
              • 2020-12-18
              • 2010-12-02
              • 2013-12-18
              相关资源
              最近更新 更多