首页 > 解决方案 > Angular 提供者 - 无论我是否使用它们,我都会得到相同的结果?

问题描述

我目前正在通过视频课程学习 Angular,现在我正在进入服务领域。

我有一个演示应用程序,使用此服务:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class LoggingService {

constructor() { }

logStatusChange(status: String)
{
  console.log("A server status changed, new status:" + status);
}
}

和一个看起来像这样的组件:

.ts

import { Component, EventEmitter, Output } from '@angular/core';
import {LoggingService} from "../logging.service";

@Component({
  selector: 'app-new-account',
  templateUrl: './new-account.component.html',
  styleUrls: ['./new-account.component.css']
  // providers: [LoggingService]
})
export class NewAccountComponent {
  @Output() accountAdded = new EventEmitter<{name: string, status: string}>();

  constructor(private serviceLogger: LoggingService) {};

  onCreateAccount(accountName: string, accountStatus: string) {
    this.accountAdded.emit({
      name: accountName,
      status: accountStatus
    });
    this.serviceLogger.logStatusChange(accountStatus);
  }
}

.html

<div class="row">
  <div class="col-xs-12 col-md-8 col-md-offset-2">
    <div class="form-group">
      <label>Account Name</label>
      <input
        type="text"
        class="form-control"
        #accountName>
    </div>
    <div class="form-group">
      <select class="form-control" #status>
        <option value="active">Active</option>
        <option value="inactive">Inactive</option>
        <option value="hidden">Hidden</option>
      </select>
    </div>
    <button
      class="btn btn-primary"
      (click)="onCreateAccount(accountName.value, status.value)">
      Add Account
    </button>
  </div>
</div>

如您所见,我注释掉了 providers 数组,因为无论有没有它,我的应用程序都一样工作,我不明白为什么。

我不知道为什么我需要声明提供者数组。我认为它有助于 Angular 在这里创造这个价值:

constructor(private serviceLogger: LoggingService) {};

但实际上并没有。(因为无论有没有提供程序数组,我的应用程序的工作方式完全相同)

谁能帮我理解为什么我的应用程序行为相同以及为什么我需要提供程序数组?

谢谢。

标签: angular

解决方案


关键是这样的:

providedIn: 'root'

在 Angular 6 前后,这开始成为提供单例服务的首选方法。这会自动在根注入器中为您注册服务。如果未指定,您只需providers在模块或组件的数组中指定它。

角度依赖注入文档

如果您需要更好的理解,我建议您阅读文档,有很多要解释的内容,此时您可能并不关心其中的大部分内容。注入器的层次结构从根->模块->组件开始。

在 StackBlitz 上设置了一个示例:

  • MyService 不使用 'providedIn',因此必须在 provider 数组中的某个级别(模块/组件)中声明
  • 单个模块 AppModule 有一个列出了 MyService 的 providers 数组。这意味着模块中的任何子组件都可以访问单个实例 MyService 以进行依赖注入,因为 MyService 的新实例仅在需要时为该模块创建。
  • ComponentA 和 ComponentC 没有提供程序数组。当他们在构造函数中请求 MyService 时,Angular 会搜索依赖注入树并在 AppModule 中找到它,因此他们使用该实例。
  • ComponentB确实有一个 providers 数组。当它在 ComponentB 的构造函数中被请求时,Angular 再次从 Component->Module->Root 向上遍历树,但它会看到组件的注入器中提供的服务,因此它甚至不会检查模块或根注入器。所以每次创建 ComponentB 时,都会创建并使用一个新的 MyService 实例。

我的服务:

import { Injectable } from '@angular/core';

let INSTANCE_NUMBER = 0;

@Injectable()
export class MyService {
  instanceNumber: number;

  constructor() {
    INSTANCE_NUMBER++;
    this.instanceNumber = INSTANCE_NUMBER;
  }
}

每个组件都简单地显示一条来自其 MyService 实例的带有 instanceNumber 的消息。您可以看到每个组件有 5 个。ComponentA 和 ComponentC 的所有十个实例共享 MyService 的实例“1”。每个 ComponentB 都有一个单独的 MyService 实例,从“2”到“6”。

在服务中使用“providedIn”更容易。通常,您不应该在服务中存储状态,也不需要单独的实例,因此为整个应用程序提供一个实例就可以了。 如果您确实需要为某个模块或组件配置不同的服务,您可以将其列出并在模块或组件的 providers 数组中进行配置。


推荐阅读