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

NGRX中Reducer未触发?如何正确将Reducer接入Store?

问题描述

我在服务中dispatch addHero动作时,能看到每个Hero对应的"obtaining"和"dispatched"日志,但Reducer似乎未被调用。该服务的run方法在ngOnInit钩子中触发。

更新:我已将appReducer包装为一个函数,用于记录每次Reducer调用并调用实际Reducer,但仍未看到相关日志,推测可能在Reducer接入Store的环节存在疏漏。我在module.ts的imports中尝试了如下代码:

StoreModule.forRoot(appReducer)

相关代码

服务代码

export class GetTheActualListOfHeroesService {

  store: Store<AppStore>;

  run(): void {
    console.log("GetTheActualListOfHeroesService")
    obtainHeroesService().forEach(hero => {
      console.log("obtaining", hero)
      this.store.dispatch(addHero(hero))
      console.log("dispatched")
    }
    )
  };

  constructor(appStore: Store<AppStore>) {
    this.store = appStore;
  }

}

Reducer代码(未看到"addHero"日志)

export const initialState: AppStore = {
  heroes: [],
  filterString: "",
  selectedHero: undefined
}

export const appReducer = createReducer(
  initialState,
  on(addHero, (state: AppStore, hero) => {
    console.log("addHero", hero)
    state.heroes.push(hero);
    console.log(state)
    return state;
  }),
);

动作定义

export const addHero = createAction('add Hero', props<Hero>());

模块定义

@NgModule({
  declarations: [
    HeroesComponent,
    HeroeditorComponent,
    HeroitemComponent,
    HeroListComponent,
    HeroFilterComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    StoreModule.forRoot(appReducer)
  ],
  providers: [
    SelectedHeroRepository,
    HeroFilterRepository,
    GetTheActualListOfHeroesService,
    IsThisHeroSelectedForEditingService,
    SelectHeroForEditingService,
    InitializeStatesService,
    SelectHeroesWithMatchingNamesService,
  ],
  bootstrap: [HeroesComponent]
})
export class Angulartest { }

请问我忽略了什么明显问题?


问题排查与解决

1. StoreModule.forRoot参数格式错误

NgRx的StoreModule.forRoot()要求传入键值对对象(state分片名称对应reducer),而非直接传入reducer函数。你当前的写法不符合规范,修改模块中的imports:

StoreModule.forRoot({ app: appReducer })

这里的app是state的分片标识,后续获取state时需要对应这个名称,比如store.select(state => state.app.heroes)。

2. Reducer直接修改原state对象

NgRx要求Reducer是纯函数,绝对不能直接修改原state,必须返回全新的state对象。你用state.heroes.push(hero)直接修改原数组,会导致NgRx无法检测到state变化,同时违反不可变数据原则。修改Reducer代码:

export const appReducer = createReducer(
  initialState,
  on(addHero, (state: AppStore, hero) => {
    console.log("addHero", hero)
    // 扩展运算符创建新数组,返回全新state对象
    return {
      ...state,
      heroes: [...state.heroes, hero]
    };
  }),
);

3. 确认obtainHeroesService的返回值类型

如果obtainHeroesService()返回的是Observable,不能直接用forEach遍历,需要改用subscribe:

obtainHeroesService().subscribe(heroes => {
  heroes.forEach(hero => {
    console.log("obtaining", hero)
    this.store.dispatch(addHero(hero))
    console.log("dispatched")
  })
})

4. 验证组件中服务的调用逻辑

确保组件的ngOnInit中正确调用了服务的run方法,且服务已被正确注入:

@Component({...})
export class HeroesComponent implements OnInit {
  constructor(private heroService: GetTheActualListOfHeroesService) {}

  ngOnInit(): void {
    this.heroService.run();
  }
}

内容的提问来源于stack exchange,提问作者Árpád Magosányi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 15:55:25