Angular 同一NgRx功能模块的独立实例
我正在使用NgRx 5进行Angular 5项目。到目前为止,我已经实现了一个框架应用程序和一个名为“搜索”的功能模块,它以封装的方式(通过使用Angular 同一NgRx功能模块的独立实例,angular,ngrx,ngrx-store,Angular,Ngrx,Ngrx Store,我正在使用NgRx 5进行Angular 5项目。到目前为止,我已经实现了一个框架应用程序和一个名为“搜索”的功能模块,它以封装的方式(通过使用forFeature语法)处理自己的状态、操作和简化程序 此模块有一个根组件(搜索容器),它呈现整个子组件树-它们一起构成搜索UI和功能,它有一个复杂的状态模型和大量的操作和简化程序 强烈要求如下: 功能模块应相互隔离地导入, 根据消费者应用程序的要求 同一功能的多个实例应在同一父级内共存(例如,具有单独上下文的单独选项卡) 实例不应该具有共享的内部状态
forFeature
语法)处理自己的状态、操作和简化程序
此模块有一个根组件(搜索容器
),它呈现整个子组件树-它们一起构成搜索UI和功能,它有一个复杂的状态模型和大量的操作和简化程序
强烈要求如下:
放在一起并确保它们独立运行?例如,我想在小部件的一个实例中分派一个搜索操作,而不是在所有小部件中看到相同的搜索结果
任何建议都将不胜感激。谢谢 我遇到了一个与你类似的问题,并想出了以下解决方法 重申您的要求,以确保我正确理解:
- 您有一个模块“搜索”,其中包含自己的组件/状态/减速器/动作等
- 您希望重用该模块以拥有许多搜索选项卡,这些选项卡的外观和行为都相同
export interface SearchStates {
[searchStateId: string]: SearchState;
}
export interface SearchState {
results: string;
}
export interface SearchMetadata {
id: string;
}
export const search = (params: string, meta: SearchMetadata) => ({
type: 'SEARCH',
payload: params,
meta
});
export const searchReducer = (state: SearchStates = {}, action: any) => {
switch (action.type) {
case 'SEARCH':
const id = action.meta.id;
state = createStateIfDoesntExist(state, id);
return {
...state,
[id]: {
...state[id],
results: action.payload
}
};
}
return state;
};
操作如下所示:
export interface SearchStates {
[searchStateId: string]: SearchState;
}
export interface SearchState {
results: string;
}
export interface SearchMetadata {
id: string;
}
export const search = (params: string, meta: SearchMetadata) => ({
type: 'SEARCH',
payload: params,
meta
});
export const searchReducer = (state: SearchStates = {}, action: any) => {
switch (action.type) {
case 'SEARCH':
const id = action.meta.id;
state = createStateIfDoesntExist(state, id);
return {
...state,
[id]: {
...state[id],
results: action.payload
}
};
}
return state;
};
减速器的操作方式如下:
export interface SearchStates {
[searchStateId: string]: SearchState;
}
export interface SearchState {
results: string;
}
export interface SearchMetadata {
id: string;
}
export const search = (params: string, meta: SearchMetadata) => ({
type: 'SEARCH',
payload: params,
meta
});
export const searchReducer = (state: SearchStates = {}, action: any) => {
switch (action.type) {
case 'SEARCH':
const id = action.meta.id;
state = createStateIfDoesntExist(state, id);
return {
...state,
[id]: {
...state[id],
results: action.payload
}
};
}
return state;
};
您的模块为root用户提供一次减缩器和可能的效果,并为每个功能(也称为搜索)提供一个元数据配置:
// provide this inside your root module
@NgModule({
imports: [StoreModule.forFeature('searches', searchReducer)]
})
export class SearchModuleForRoot {}
// use forFeature to provide this to your search modules
@NgModule({
// ...
declarations: [SearchContainerComponent]
})
export class SearchModule {
static forFeature(config: SearchMetadata): ModuleWithProviders {
return {
ngModule: SearchModule,
providers: [{ provide: SEARCH_METADATA, useValue: config }]
};
}
}
@Component({
// ...
})
export class SearchContainerComponent {
constructor(@Inject(SEARCH_METADATA) private meta: SearchMetadata, private store: Store<any>) {}
search(params: string) {
this.store.dispatch(search(params, this.meta);
}
}
然后,当导航到searchTab1时,将呈现SearchContainerComponent
…但我想在单个模块中使用多个SearchContainer组件
您可以在组件级别应用相同的模式:
在SearchService启动时随机创建元数据id。在SearchContainer组件内提供SearchService。
当服务被破坏时,不要忘记清理状态
@Injectable()
export class SearchService implements OnDestroy {
private meta: SearchMetadata = {id: "search-" + Math.random()}
// ....
}
@Component({
// ...
providers: [SearchService]
})
export class SearchContainerComponent implements OnInit {
// ...
}
如果希望ID具有确定性,则必须在某处对其进行硬编码,然后将其作为输入传递给SearchContainerComponent,然后使用元数据初始化服务。这当然会使代码更复杂一些
工作示例
每个模块:
每个组件:
找到了解决方法吗?@ParthGhiya不幸没有。我所做的是在创建时为每个容器分配ID。因此,特性的状态看起来像{id->containerState}的映射。处理这些会增加很多额外的复杂性,例如为每个容器的子组件集提供正确的id、分派id感知操作、修饰还原程序以修改容器状态以及使用动态生成的选择器,因为您无法将容器id作为参数传递给ngrx选择器。最后,我围绕容器管理编写了一个完整的元框架:(感谢您提供详细的答案-这看起来与我最终实现的内容非常相似,只是有些不同,但核心思想是相同的。因此,我很高兴将此答案标记为一个可行的解决方案。我在调度操作时封装搜索元数据逻辑,并在Reducer中处理它们方面做了更多的工作和效果,但它仍然感觉像很多样板。我希望在某个时候ngrx团队能够为这个问题提供一个更精简的解决方案。谢谢,这对我在项目中实现虚拟标签有很大帮助