我遇到了注入动态加载的组件的服务的奇怪行为。考虑以下服务
@Injectable({
providedIn: 'root'
})
export class SomeService {
private random = Math.random() * 100;
constructor() {
console.log('random', this.random);
}
}
该服务作为对两个组件的依赖关系而添加。第一个组件是延迟加载模块的一部分。而第二个是动态加载的。以下服务使用动态组件加载模块
export const COMPONENT_LIST = new InjectionToken<any>('COMPONENT_LIST');
export const COMPONENT_TYPE = new InjectionToken<any>('COMPONENT_TYPE');
@Injectable({
providedIn: 'root'
})
export class LoaderService {
constructor(
private injector: Injector,
private compiler: Compiler,
) { }
getFactory<T>(componentId: string): Observable<ComponentFactory<T>> {
// COMPONENT_LIST is passed through forRoot() from the module that declares first component
const componentList = this.injector.get(COMPONENT_LIST);
const m = componentList.find(m => m.componentId === componentId);
const promise: Promise<ComponentFactory<T>> = (!m) ? null :
m.loadChildren
.then((mod: any) => {
return this.compiler.compileModuleAsync(mod);
})
.then((mf: NgModuleFactory<any>) => {
const mr: NgModuleRef<any> = mf.create(this.injector);
const type: Type<T> = mr.injector.get<Type<T>>(COMPONENT_TYPE); // DYNAMIC_COMPONENT is provided in loaded module
return mr.componentFactoryResolver.resolveComponentFactory<T>(dynamicComponentType);
});
return from(promise);
}
}
在同一模块中,我声明以下组件(放置动态加载的组件)和指令
@Component({
selector: 'dynamic-wrapper',
template: `<ng-container dynamicItem></ng-container>`
})
export class DynamicWrapperComponent implements AfterViewInit, OnDestroy {
@Input() itemId: string;
@Input() inputParameters: any;
@ViewChild(DynamicItemDirective)
private dynamicItem: DynamicItemDirective;
private unsubscribe$: Subject<void> = new Subject();
constructor(
private loaderService: LoaderService
) { }
ngAfterViewInit(): void {
this.loaderService.getComponentFactory(this.itemId).subscribe((cf: ComponentFactory<any>) => {
this.dynamicItem.addComponent(cf, this.inputParameters);
});
}
}
...
@Directive({
selector: '[dynamicItem]'
})
export class DynamicItemDirective {
constructor(protected viewContainerRef: ViewContainerRef) { }
public addComponent(cf: ComponentFactory<any>, inputs: any): void {
this.viewContainerRef.clear();
const componentRef: ComponentRef<any> = this.viewContainerRef.createComponent(cf);
Object.assign(componentRef.instance, inputs);
// if I do not call detectChanges, ngOnInit in loaded component will not fire up
componentRef.changeDetectorRef.detectChanges();
}
}
SomeService
是在单独的模块中定义的,该模块同时导入具有第一个组件的延迟加载模块和动态加载模块。
初始化两个组件之后console.log('random', this.random)
,尽管providedIn: 'root'
在装饰器中,我仍在控制台中看到带有两个不同数字的输出。发生这种奇怪行为的原因是什么?
延迟加载的模块不会providedIn: 'root'
像预期的那样做出反应。仅当导入服务的模块没有延迟加载时,此选项才会将服务推送到AppModule(根模块)。
因为其中SomeService
定义的模块启动了两次!(可以将console.log放在此模块的构造函数中)-因此该服务被启动了两次(我在我的项目延迟加载平台中自己遇到了这个问题)。
SomeService
启动两次?loadChildren
或moduleFactory.create(this.injector)
不保留延迟加载的模块的缓存。他们启动一个模块,并将其喷油器作为叶子连接到输入喷油器。
如果包含的模块SomeService
是从创建的moduleFactory.create
-您可以添加缓存层以返回缓存的已启动的延迟加载模块。
例如:
private lazyLoadedModulesCache: Map<Type<any>, NgModuleRef<any>>;
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句