在NgModules过渡独立组件时,如何为独立组件提供Root Store?
问题
在基于NgModules架构的项目逐步迁移到独立组件的过程中,目前仍通过app.module引导应用(无法使用bootstrapApplication),遇到了独立组件注入根Store的问题:如果在路由的providers中添加provideStore(reducers, {metaReducers}),会触发Store已重复声明的错误。
现有代码片段
app.module.ts
@NgModule({ declarations: [ AppComponent, ErrorPageComponent, FallbackComponent, ShouldLoginComponent ], imports: [ BrowserAnimationsModule, BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), BrowserModule, HttpClientModule, IdentityModule.forRoot(), CoreModule, StoreModule.forRoot(reducers, {metaReducers}), // 已在根模块注册的全局Store // ...其他导入 ], bootstrap: [AppComponent] }) export class AppModule { }
reducers.ts
export interface AppState { activities: ActivityState, auth: AuthState, chatflows: ChatFlowsState, kb: KbState, layout: LayoutState, properties: PropertiesState, router: RouterReducerState<any>; savedreplies: SavedRepliesState, settings: SettingsState, tickets: TicketsState, visitors: VisitorState } export const reducers: ActionReducerMap<AppState> = { activities: activityReducer, auth: authReducer, chatflows: chatFlowsReducer, kb: KbStateReducer, layout: layoutReducer, properties: propertiesReducer, router: routerReducer, savedreplies: savedRepliesReducer, settings: settingsReducer, tickets: TicketsStateReducer, visitors: visitorsReducer }; export const metaReducers: MetaReducer<AppState>[] = [];
routes.ts
const routes: Routes = [ { path: '', component: BaseComponent, children: [ { path: 'conversations', canActivate: [IdentityGuardWithForcedLogin], loadComponent: () => import('../conversations/conversations.components').then(m => m.ConversationsComponent), providers: [ provideStore(reducers, {metaReducers}), // 此处重复注册导致错误 provideEffects([ActivityEffects, VisitorsEffects, TicketsEffects]), ] }, // ...其他路由 ] } ];
conversations.component.ts
@Component({ selector: 'conversations', templateUrl: './conversations.component.html', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [VisitorsComponent, MessagesComponent, InfoComponent] }) export class ConversationsComponent{ constructor( private store: Store<AppState>, // 需要注入全局根Store private inboxService: ConversationsService, private modalService: NgbModal, ) { // ...组件逻辑 } }
解决方法
1. 移除路由中重复的provideStore声明
由于根模块AppModule已经通过StoreModule.forRoot()注册了全局单例的根Store,独立组件可以直接注入Store<AppState>,无需在路由或组件的providers中重复声明provideStore。
修改后的routes.ts:
const routes: Routes = [ { path: '', component: BaseComponent, children: [ { path: 'conversations', canActivate: [IdentityGuardWithForcedLogin], loadComponent: () => import('../conversations/conversations.components').then(m => m.ConversationsComponent), providers: [ // 移除重复的provideStore provideEffects([ActivityEffects, VisitorsEffects, TicketsEffects]), ] }, // ...其他路由 ] } ];
2. 验证组件注入逻辑
保持ConversationsComponent的注入代码不变,因为全局Store已经在根模块注册,Angular的依赖注入系统会自动找到并注入这个单例实例:
constructor( private store: Store<AppState>, // 正常注入全局Store private inboxService: ConversationsService, private modalService: NgbModal, ) { // ...组件逻辑 }
3. 若需注册Feature Store(可选)
如果该独立组件需要访问额外的Feature Store,不要使用provideStore,而是用provideState来注册特定的Feature reducer:
// 假设需要注册一个名为"conversations"的Feature Store providers: [ provideState('conversations', conversationReducer), provideEffects([ActivityEffects, VisitorsEffects, TicketsEffects]), ]
这样既能避免重复注册根Store的错误,又能正常在独立组件中使用全局或特定Feature的Store实例。
内容的提问来源于stack exchange,提问作者Yehia A.Salam
相关产品推荐
相关产品推荐

