NgRx Entity Adapter如何添加第二个无关类?
NgRx 多独立实体状态管理指导
问题描述
现有一套基于Class1的可运行NgRx状态配置,需要在全局状态中管理另一个与Class1完全无关的Class2,不清楚该如何布局,疑问点包括:
- 是否需要使用第二个
EntityAdapter? - 是否需要为
Class2新建一个reducer文件?
现有reducer代码如下:
import { createReducer, on } from '@ngrx/store'; import { ActionTypes } from '@state/actions/action-types'; import { createEntityAdapter, EntityState } from '@ngrx/entity'; import { Class1 } from '../../models/class1'; import { Class2 } from '../../models/class2'; export interface MyState extends EntityState<Class1>{ status: 'loading' | 'error' | 'success'; errorMsg: string; } export const adapter = createEntityAdapter<Class1>(); // If I want to use a second class, do I just create a second adapter? export const adapter2 = createEntityAdapter<Class2>(); export const initialState = adapter.getInitialState({ status: 'loading', errorMsg: '', }); export const stuffReducer = createReducer( initialState, on(ActionTypes.StockpileActions.loadClass1Stuff, (state, action) => adapter.setAll(action.stuff, {...state, status: 'success', errorMsg: ''}) ), // Can I use the second adapter to access the related actions for that class? on(ActionTypes.StockpileActions.loadClass2Stuff, (state, action) => adapter2.setAll(action.stuff, {...state, status: 'success', errorMsg: ''}) ), ); export const { selectAll } = adapter.getSelectors();
解答
核心结论
- 需要为
Class2创建独立的EntityAdapter:每个实体类型对应自己的EntityAdapter,这是NgRx Entity管理不同实体的标准做法。 - 强烈建议为
Class2新建独立的reducer、状态接口、selector文件:因为两个实体完全无关,拆分管理符合模块化原则,避免逻辑耦合,后续维护和扩展更方便。
具体实现步骤
1. 拆分状态结构
为每个实体创建独立的状态接口,再通过根状态整合两个切片:
// src/app/state/class1/class1.state.ts import { EntityState } from '@ngrx/entity'; import { Class1 } from '../../models/class1'; export interface Class1State extends EntityState<Class1> { status: 'loading' | 'error' | 'success'; errorMsg: string; } // src/app/state/class2/class2.state.ts import { EntityState } from '@ngrx/entity'; import { Class2 } from '../../models/class2'; export interface Class2State extends EntityState<Class2> { status: 'loading' | 'error' | 'success'; errorMsg: string; } // src/app/state/app.state.ts(根状态) export interface AppState { class1: Class1State; class2: Class2State; }
2. 为每个实体创建独立的Reducer和Adapter
每个实体的状态更新逻辑完全隔离,互不影响:
Class1的Reducer(class1.reducer.ts):
import { createReducer, on } from '@ngrx/store'; import { createEntityAdapter } from '@ngrx/entity'; import { Class1State } from './class1.state'; import { Class1 } from '../../models/class1'; import { ActionTypes } from '../actions/action-types'; export const class1Adapter = createEntityAdapter<Class1>(); export const initialClass1State: Class1State = class1Adapter.getInitialState({ status: 'loading', errorMsg: '' }); export const class1Reducer = createReducer( initialClass1State, on(ActionTypes.StockpileActions.loadClass1Stuff, (state, action) => class1Adapter.setAll(action.stuff, { ...state, status: 'success', errorMsg: '' }) ), // 可添加Class1相关的其他action处理逻辑 ); export const { selectAll: selectAllClass1 } = class1Adapter.getSelectors();
Class2的Reducer(class2.reducer.ts):
import { createReducer, on } from '@ngrx/store'; import { createEntityAdapter } from '@ngrx/entity'; import { Class2State } from './class2.state'; import { Class2 } from '../../models/class2'; import { ActionTypes } from '../actions/action-types'; export const class2Adapter = createEntityAdapter<Class2>(); export const initialClass2State: Class2State = class2Adapter.getInitialState({ status: 'loading', errorMsg: '' }); export const class2Reducer = createReducer( initialClass2State, on(ActionTypes.StockpileActions.loadClass2Stuff, (state, action) => class2Adapter.setAll(action.stuff, { ...state, status: 'success', errorMsg: '' }) ), // 可添加Class2相关的其他action处理逻辑 ); export const { selectAll: selectAllClass2 } = class2Adapter.getSelectors();
3. 注册Reducer到全局Store
在你的状态模块中,将两个Reducer注册到Store:
import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { AppState } from './app.state'; import { class1Reducer } from './class1/class1.reducer'; import { class2Reducer } from './class2/class2.reducer'; @NgModule({ imports: [ StoreModule.forRoot<AppState>({ class1: class1Reducer, class2: class2Reducer }) ] }) export class StateModule {}
为什么不共用一个Reducer?
- 状态冲突:你原来的代码中,
Class1和Class2共享同一个status和errorMsg,会导致一个实体的加载状态覆盖另一个的,完全不符合业务需求。 - 违反单一职责:一个Reducer只应处理一类实体的状态更新,混写会导致逻辑臃肿,后续定位问题、扩展功能都非常困难。
- 扩展性差:后续添加更多实体时,单个Reducer会越来越庞大,拆分结构可以轻松扩展新实体的状态管理。
内容的提问来源于stack exchange,提问作者Scottish Smile
相关产品推荐
相关产品推荐

