You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();

解答

核心结论

  1. 需要为Class2创建独立的EntityAdapter:每个实体类型对应自己的EntityAdapter,这是NgRx Entity管理不同实体的标准做法。
  2. 强烈建议为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 02:17:18