Circular Dependency w Angular

Jak uniknąć efektu circular dependency?

Angular dostarcza nam prosty sposób na dynamiczne generowanie komponentów, ale czasami pojawia się problem.

Problem

Załóżmy, że mamy dwa komponenty i serwis do dynamicznego renderowanie komponentów. Serwis posiada metodę render, która akceptuje typ komponentu jako argument np. OneComponent.

OneComponent używa naszego serwisu do wyrenderowania komponentu TwoComponent, a komponent TwoComponent używa serwisu do wyrenderowania komponentu OneComponent.

Ostrzeżenie circular dependency

Dzieje się to, ponieważ OneComponent importuje TwoComponent, a TwoComponent importuje OneComponent. Chaos, prawda?

Jakiś czas temu odkryłem ciekawy sposób na rozwiązanie tego problemu. W tym celu użyjemy InjectionsTokens i dodamy je do naszego komponentu jako providers.

Stwórzmy COMPONENT_ONE_TOKEN (COMPONENT_TWO_TOKEN token jest stworzony podobnie).

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

export const COMPONENT_ONE_TOKEN = new InjectionToken<any>('ComponentOneToken');

Dodajmy tokeny w module

@NgModule({
  imports: [
    CommonModule,
  ],
  declarations: [
    OneComponent,
    TwoComponent
  ],
  entryComponents: [
    OneComponent,
    TwoComponent
  ],
  providers: [
    RenderService,
    { provide: COMPONENT_ONE_TOKEN, useValue: OneComponent },
    { provide: COMPONENT_TWO_TOKEN, useValue: TwoComponent }
  ]
})
export class SomeModule {
}

Pozwala nam to na wstrzyknięcie klas komponentów

@Component({
  selector: 'app-one',
  templateUrl: './one.component.html',
  styleUrls: ['./one.component.scss']
})
export class OneComponent {
  constructor(@Inject(COMPONENT_TWO_TOKEN) private componentTwo) {
  }
}

Zmieni to sposób używamy metody render w serwisie z service.render(TwoComponent) na service.render(this.componentTwo).

Podsumowanie

Rozwiązanie jest dość skomplikowane. Innym sposobem jest na pewno lepsza architektura komponentów, która nie doprowadzi do ostrzeżeń o circular dependency. Czasami się nie da.

Default image
Wojciech Szućko
Jestem Angular Developerem. Przedstawiam techniki i technologie, które wykorzystuje w codziennej pracy z web aplikacjami. Tworzyłem projekty między innymi dla Bank Pekao S.A., AlphaTauri czy Playmobil.