筆者在 Angular 實際專案開發中曾經遇到這樣一個需求:
我們想建立一個共享模組,它將包含一個配置來設定布林值(作為標誌)以啟用或禁用其他模組的某些功能。 其他模組可以在 Angular 應用程式的引導期間載入,也可以是延遲載入的模組。
ForRoot 的使用場景
當我們想要跨應用程式維護服務的單個例項(單例)時使用,這些應用程式也將具有延遲載入的模組。
舉個例子,看看託管在 StackBlitz 上這個演示程式碼,其中計數器對於急切和延遲載入模組的行為不同。
sharedModule 的 provider 陣列裡匯入了這個服務:
在此示例中,我們共享一項服務以跟上計數器值。 每次任何元件增加儲存在計數器服務中的值時,我都想與所有元件共享它。
我在 app.routes.ts 裡定義了一個路由陣列 routing
:
上圖透過 LazyLoad 的方式,載入 LazyModule
,後者的實現:
LazyModule 匯入 SharedModule,是為了使用其計數器 CounterService:
問題是當我們嘗試引入延遲載入模組時。 請注意延遲載入的元件如何不共享相同的計數器值。 當僅使用預載入元件時,如果您使用共享服務,下面的示例將起作用,但請注意延遲載入元件的行為方式。惰性元件獲取自己的服務例項。
但這個解決方案的問題是:我們在 Eager Load 的 Component 裡點選 Counter 按鈕,增加計數器的值後,點選 Lazy 超連結,進入 LazyModule 裡的 Component,我們期望此時在 Component 裡顯示的值也為 7:
然而事與願違,Lazy Component 裡的值為 0:
計數器由駐留在 SharedModule 下的 CounterService 維護。 由於延遲載入的模組建立了自己的服務例項
,我們失去了 Angular 服務的單例行為。
為了解決這個問題,我們需要引入 forRoot() 的概念。 可以在這個演示中看到工作示例。這是同樣的原因,我們將它與 RouterModule 一起使用,以幫助 RouterService 瞭解具有多個模組的應用程式行為。
RouterModule.forRoot(ROUTES)
修改後的解決方案,SharedModule 的實現程式碼:
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CounterService } from './counter.service';
@NgModule({
})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: SharedModule,
providers: [ CounterService ]
}
}
}
App module 裡呼叫這個方法:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { SharedModule } from './shared/shared.module';
import { AppComponent } from './app.component';
import { EagerComponent } from './eager.component';
import { routing } from './app.routes';
@NgModule({
imports: [ BrowserModule, SharedModule.forRoot(), routing ],
declarations: [ AppComponent, EagerComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
修改之後的程式碼連結。
之後可以在 Eager Load 和 Lazy Load Component 之間任意切換,單例模式的行為能夠正常工作。