Розбираємось у scopes Angular сервісів

level

Переклад статті: https://dev.to/juliandierkes/provider-scopes-in-angular-209g

Модульна система Angular надає можливість створювати Компоненти та Сервіси. Хоча Компоненти повинні зосереджуватися на поданні, тобто на HTML-шаблоні, Сервіси повинні використовуватися для логіки застосунку. На моєму досвіді, вони в основному використовуються для HTTP-запитів, але Сервіси можуть виконувати й інші функції, такі як логування або валідація. Багато Сервісів будуть використовуватися повторно протягом одного застосунку.

При повторному використанні Сервісів важливо враховувати область, у якій ви хочете їх надавати.

Angular фактично пропонує три області:

  1. Коренева область (Root Scope)

  2. Область модуля (Module Scope)

  3. Область компонента (Component Scope)

Root Scope (Глобальна область)

Глобальна область є найбільш часто використовуваною для надання Сервісів, оскільки вона є також областю за замовчуванням при створенні Сервісу через Angular CLI.

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

Аргумент providedIn: 'root' у згенерованому сервісі означає, що сервіс буде існувати у глобальному модулі, тобто в AppModule. Таким чином, сервіс буде синглтоном, тобто буде існувати лише один екземпляр цього сервісу, навіть якщо його буде інжектовано у кілька інших модулів або використано у кількох компонентах або директивах.

Підказка: використання аргументу providedIn у @Injectable також може оптимізувати розміри бандлів, якщо сервіс не використовується, що особливо корисно при написанні бібліотек. Детальніше в Angular Docs.

Module Scope (Модульна область)

Аналогічно, ми можемо створити сервіс у модульній області:

@Injectable({
  providedIn: 'ExampleModule'
})
export class ExampleService {}

Але що, якщо ми не хочемо ділитися сервісом між модулями? Тоді ми можемо використовувати масив providers у відповідному @NgModule:

@NgModule({
  ...
  providers: [
    ExampleService
  ]
})
export class ExampleModule {}

Таким чином, екземпляр сервісу буде створено для кожного модуля. Якщо сервіс додано до масиву providers кількох модулів, то кожен модуль отримує свій власний екземпляр сервісу ExampleService.

Component Scope (Компонентна область)

Ми також можемо створити окремий екземпляр сервісу для компонента, використовуючи компонентну область:

@Component({
  ...
  providers: [ExampleService]
})
export class ExampleComponent{}

Давайте побачимо це в дії

Давайте створимо приклад застосунку, використовуючи модульну та компонентну області.

Я використав Angular CLI для створення проєкту зі наступною структурою:

Project structure
Структура проєкту

Є лише один сервіс ExampleService, який знаходиться у SharedModule:

@Injectable()
export class ExampleService {
  name = "Frank";

  constructor() {}
}

Цей модуль, а отже і сервіс, використовується у двох інших модулях, які обидва імпортуються в AppModule.

  1. ComponentScopeModule, який використовує компонентну область і складається з двох компонентів.

    1. Example1Component, який надає вхід для властивості name сервісу:

@Component({
  selector: 'component-scope-example1',
  template: `<input [(ngModel)]="service.name">`,
  providers: [ExampleService]
})
export class Example1Component {
  constructor(readonly service: ExampleService) {}
}

2. Example2Component, який просто відображає властивість name сервісу:

@Component({
  selector: 'component-scope-example2',
  template: `<p>{{service.name}}</p>`,
  providers: [ExampleService]
})
export class Example2Component {
  constructor(readonly service: ExampleService) {}
}
  1. ModuleScopeModule, який використовує модульну область і складається з двох схожих компонентів. Різниця в тому, що компоненти не використовують масив providers. Натомість сервіс надається у модулі:

@NgModule({
  declarations: [Example1Component, Example2Component],
  imports: [
    CommonModule,
    SharedModule,
    FormsModule
  ],
  exports: [
    Example1Component,
    Example2Component
  ],
  providers: [
    ExampleService     <--- сервіс надається тут
  ]
})
export class ModuleScopeModule {
}

Усі чотири компоненти відображаються за допомогою AppComponent:

<div>
  <h1>Module Scoped</h1>
  <module-scope-example1></module-scope-example1>
  <module-scope-example2></module-scope-example2>
</div>
<div>
  <h1>Component Scoped</h1>
  <component-scope-example1></component-scope-example1>
  <component-scope-example2></component-scope-example2>
</div>

І нарешті, ось що ми отримуємо:

Result in action

Ми бачимо, що в секції "Module Scoped" обидва компоненти використовують один і той самий сервіс, і тому введення в першому компоненті змінює виведення у другому компоненті. У секції "Component Scoped" це не працює, оскільки створюються два екземпляри сервісу, по одному для кожного компонента.

Підтримати автора можна зареєструвавшись на сайті Whitebit за реферальним посиланням https://whitebit.com/referral/6f7c7706-ec7d-4a60-8021-adf88b3a9559

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Crypto blogger
Crypto blogger@crypto_blogger

776Прочитань
5Автори
7Читачі
Підтримати
На Друкарні з 24 лютого

Більше від автора

Вам також сподобається

  • ДЖУНІОР 2023

    Якісь проблеми диктуються ринком, якісь створюються гівняними курсами, або очікуваннями кандидатів.

    Теми цього довгочиту:

    It
  • Майбутнє фронтенду — Пайтон?🤔

    PyWeb - фронтенд фреймворк, написаний на Пайтоні, мого авторства 🤓 Щоб запускати Пайтон в браузері використовується Pyodide та WebAssembly

    Теми цього довгочиту:

    Python

Коментарі (0)

Підтримайте автора першим.
Напишіть коментар!

Вам також сподобається

  • ДЖУНІОР 2023

    Якісь проблеми диктуються ринком, якісь створюються гівняними курсами, або очікуваннями кандидатів.

    Теми цього довгочиту:

    It
  • Майбутнє фронтенду — Пайтон?🤔

    PyWeb - фронтенд фреймворк, написаний на Пайтоні, мого авторства 🤓 Щоб запускати Пайтон в браузері використовується Pyodide та WebAssembly

    Теми цього довгочиту:

    Python