ngrx 效果模块 - 在了解提供程序使用情况方面需要帮助



我试图了解 Angular 中提供者工厂的使用。 我理解角度文档中提供的示例。

但是,我在 ngrx EffectsModule (effects_module.ts) 中遇到了相当不寻常的提供程序工厂用法。

@NgModule({})
export class EffectsModule {
static forFeature(featureEffects: Type<any>[]): ModuleWithProviders {
return {
ngModule: EffectsFeatureModule,
providers: [
featureEffects,
{
provide: FEATURE_EFFECTS,
multi: true,
deps: featureEffects,
useFactory: createSourceInstances,
},
],
};
}
// *** <snip> forRoot method for brevity
}
export function createSourceInstances(...instances: any[]) {
return instances;
}

我明白multi:true的目的.

但是,我很难弄清楚为什么featureEffects会被声明为提供者,并被用作FEATURE_EFFECTS的依赖项 -createSourceInstances(...instances: any[])实现了什么?

这种模式是什么,在哪里可以使用它?

让我们从@ngrx/effects文档开始。

我们需要做的第一件事是创建一个AuthEffects服务

@Injectable()
export class AuthEffects {
@Effect()
...
constructor(private http: HttpClient, private actions$: Actions) {}
}

我们如何记录效果?

很简单:

EffectsModule.forRoot([AuthEffects])

EffectsModule.forFeature([AuthEffects])

现在,让我们停在这里,想想AuthEffects是什么.

AuthEffects只是普通的角度服务,可以有任何依赖关系(在这种情况下是HttpClientActions),这些依赖关系将在Angular DI系统的帮助下解决。

我们正在将这项服务传递给EffectsModule,我们还可以创建更多效果:

EffectsModule.forFeature([AuthEffects, MySecondEffects, ...])

现在,让我们想象一下我们是EffectsModule的作者。

我们让用户有机会通过创建角度服务来提供任何效果计数。我们将在库中使用这些服务:

addEffects(effectSourceInstance: any) {
this.sources.addEffects(effectSourceInstance);
}

正如你所看到的,我们需要有我们提供的服务的实例,而不仅仅是类。

我们如何创建这些实例?

也许像这样?

EffectsModule.forFeature([new AuthEffects(new HttpClient(...), new Actions(...))])

当然不是!我们可以让角度DI来做到这一点:

EffectsModule.forFeature([AuthEffects])
...
forFeature(featureEffects: Type<any>[]) {
....
providers: [
featureEffects,

现在 Angular DI 知道所有这些服务以及如何创建它们。但是作为作者,我也想在我的服务中使用它们,但我不知道如何获得它们......

@NgModule({})
export class EffectsFeatureModule {
constructor(
// i need to get all effects provided by users but they are hidden in DI system
...
) {
}
}

幸运的是,我们可以提供一个令牌,该令牌将在内部使用,并且会被库的作者知道。

为此,我们正在创建InjectionToken:

export const FEATURE_EFFECTS = new InjectionToken<any[][]>(
'ngrx/effects: Feature Effects'
);

并定义FEATURE_EFFECTS令牌的配方:

featureEffects,
{
provide: FEATURE_EFFECTS,
multi: true,
deps: featureEffects,
useFactory: (...instances: any[]) => {
return instances;
},
},

multi告诉我们,这个令牌可以定义多次(即我们有几个forFeatures调用)

deps指定FEATURE_EFFECTS令牌将使用将由 Angular DI 创建的所有featureEffects实例

useFactory将这些实例作为参数。

通过这种方式,我们确切地知道注入FEATURE_EFFECTS令牌为我们提供了所有效果实例。

让我们考虑是否可以省略featureEffects,例如:

{
provide: FEATURE_EFFECTS,
multi: true,
useValue: featureEffects
},

如果我们这样做,那么我们将不会得到实例,而是类(函数)数组。但是我们需要拥有所有实例化的类,只有 Angular DI 是这里最好的朋友。

最后,虽然Angular DI是相当强大的模式,但它也有一些限制。

在 AOT 中,以下代码:

featureEffects,
{
provide: FEATURE_EFFECTS,
multi: true,
deps: featureEffects,
useFactory: (...instances: any[]) => {
return instances;
},
},

将导致错误:

中的装饰器不支持函数表达式 "效果模块" 请考虑将函数表达式更改为导出的函数。

所以这就是为什么它写成如下:

providers: [
featureEffects,
{
provide: FEATURE_EFFECTS,
multi: true,
deps: featureEffects,
useFactory: createSourceInstances,
},
],
...
export function createSourceInstances(...instances: any[]) {
return instances;
}

我们可以成功地将这些实例放入库中:

@NgModule({})
export class EffectsFeatureModule {
constructor(
...
@Inject(FEATURE_EFFECTS) effectSourceGroups: any[][],
...

最新更新