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

Angular+NgRx Effects中actions$与服务注入为undefined的问题求助

解决Angular NgRx Effects依赖注入undefined异常

问题现象

在Angular项目中使用NgRx Effects时,NoteEffects类构造函数中的actions$和noteService被注入为undefined,导致this.actions$.pipe调用失败,抛出以下错误:

TypeError: Cannot read properties of undefined (reading 'pipe')
at note.effects.ts:17:19
at createEffect (ngrx-effects.mjs:85:47)
at <instance_members_initializer> (note.effects.ts:16:16)
at new _NoteEffects (note.effects.ts:11:3)
at Object.NoteEffects_Factory [as factory] (note.effects.ts:61:6)
at core.mjs:3132:35
at runInInjectorProfilerContext (core.mjs:866:5)
at R3Injector.hydrate (core.mjs:3131:11)
at R3Injector.get (core.mjs:3005:23)
at injectInjectorOnly (core.mjs:1095:36)

问题根源

NoteEffects中loadNotes$使用箭头函数初始化,在类成员初始化阶段,构造函数尚未完成依赖注入,此时this未指向完整的类实例,导致访问this.actions$和this.noteService均为undefined。

解决方案

方案1:修正类成员初始化方式(保持类式Effects)

将箭头函数替换为普通函数,或使用Angular的inject函数直接获取依赖(Angular 14+支持):

方式A:使用inject函数获取依赖

修改note.effects.ts:

import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { NoteDetailService } from '../../note-detail.service';
import * as NoteActions from './note.actions';
import { NoteDetail } from '../../note-detail.model';
import { Actions, createEffect, ofType, inject } from '@ngrx/effects';

@Injectable()
export class NoteEffects {
  // 直接通过inject获取依赖,无需构造函数注入
  private actions$ = inject(Actions);
  private noteService = inject(NoteDetailService);

  loadNotes$ = createEffect(() =>
    this.actions$.pipe(
      ofType(NoteActions.loadNotes),
      mergeMap(() =>
        this.noteService.refreshList().pipe(
          map((notes: NoteDetail[]) => NoteActions.loadNotesSuccess({ notes })),
          catchError((error) => of(NoteActions.loadNotesFailure({ error })))
        )
      )
    )
  );
}

方式B:改用普通函数定义Effect

import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { NoteDetailService } from '../../note-detail.service';
import * as NoteActions from './note.actions';
import { NoteDetail } from '../../note-detail.model';
import { Actions, createEffect, ofType } from '@ngrx/effects';

@Injectable()
export class NoteEffects {
  constructor(
    private actions$: Actions,
    private noteService: NoteDetailService
  ) {}

  // 使用普通函数,确保this指向类实例
  loadNotes$ = createEffect(function(this: NoteEffects) {
    return this.actions$.pipe(
      ofType(NoteActions.loadNotes),
      mergeMap(() =>
        this.noteService.refreshList().pipe(
          map((notes: NoteDetail[]) => NoteActions.loadNotesSuccess({ notes })),
          catchError((error) => of(NoteActions.loadNotesFailure({ error })))
        )
      )
    );
  });
}

方案2:使用函数式Effects(NgRx 15+推荐)

无需定义类,直接通过函数创建Effect,更简洁且避免this绑定问题:

1. 修改note.effects.ts

import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { NoteDetailService } from '../../note-detail.service';
import * as NoteActions from './note.actions';
import { NoteDetail } from '../../note-detail.model';
import { Actions, createEffect, ofType, inject } from '@ngrx/effects';

export const loadNotes$ = createEffect(
  (actions$ = inject(Actions), noteService = inject(NoteDetailService)) => {
    return actions$.pipe(
      ofType(NoteActions.loadNotes),
      mergeMap(() =>
        noteService.refreshList().pipe(
          map((notes: NoteDetail[]) => NoteActions.loadNotesSuccess({ notes })),
          catchError((error) => of(NoteActions.loadNotesFailure({ error })))
        )
      )
    );
  },
  { functional: true }
);

2. 更新main.ts中的Effects配置

// 替换原有的provideEffects([NoteEffects])
provideEffects([loadNotes$]),

额外验证点

  • 确认NoteDetailService的providedIn: 'root'配置正确,确保服务已被Angular注入系统注册。
  • 检查main.ts中provideEffects已正确添加到providers数组。

内容的提问来源于stack exchange,提问作者kimrenny

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:35:53