Angular18+NGRX18中构造函数注入actions$失效问题
问题
使用Angular 18和NGRX 18时,尝试通过构造函数将actions$注入到Effect中无法正常工作,但改用inject()方法注入则一切正常。
代码示例
import { inject, Injectable } from "@angular/core"; import { Actions, createEffect, ofType } from "@ngrx/effects"; import { actionsList } from "./students.actions"; import { catchError, exhaustMap, map, of } from "rxjs"; import { StudentsRecordsService } from "../services/students-records.service"; @Injectable() export class StudentsRecordsEffects { // actions$ = inject(Actions); // studentsRecordsService = inject(StudentsRecordsService); loadStudentsRecords$ = createEffect(() => this.actions$.pipe( ofType(actionsList.callStudentsRecordsApi), exhaustMap(() => this.studentsRecordsService.getStudentsRecords().pipe( map(studentsRecords => { console.log('API Response:', studentsRecords); // Debug API Response return { type: actionsList.callStudentsRecordsApiSuccess, payload: studentsRecords } }), catchError((error) => { console.error('Error fetching students records:', error); // Debug Error return of({ type: '[Students API] Students Loaded Error' }); }), )) )); constructor( private actions$: Actions, private studentsRecordsService: StudentsRecordsService ) {} }
控制台报错
main.ts:6 TypeError: Cannot read properties of undefined (reading 'pipe') at students.effects.ts:12:59 at <instance_members_initializer> (students.effects.ts:12:26) at new _StudentsRecordsEffects (students.effects.ts:26:3) at Object.StudentsRecordsEffects_Factory [as factory] (students.effects.ts:31:3)
原因分析
类成员变量的初始化顺序早于构造函数执行。loadStudentsRecords$作为类的属性,会在构造函数注入actions$和studentsRecordsService之前被初始化,此时this.actions$还是undefined,调用pipe()自然会抛出错误。
而inject()方法属于Angular的依赖注入运行时API,它可以在类的成员初始化阶段直接获取依赖,不需要等待构造函数执行,所以能正常拿到Actions实例。
解决方案
方案1:移到构造函数内初始化
如果坚持使用构造函数注入,需要把loadStudentsRecords$的初始化逻辑移到构造函数内部,确保依赖已经注入完成后再创建Effect:
import { inject, Injectable } from "@angular/core"; import { Actions, createEffect, ofType } from "@ngrx/effects"; import { actionsList } from "./students.actions"; import { catchError, exhaustMap, map, of } from "rxjs"; import { StudentsRecordsService } from "../services/students-records.service"; @Injectable() export class StudentsRecordsEffects { loadStudentsRecords$; constructor( private actions$: Actions, private studentsRecordsService: StudentsRecordsService ) { this.loadStudentsRecords$ = createEffect(() => this.actions$.pipe( ofType(actionsList.callStudentsRecordsApi), exhaustMap(() => this.studentsRecordsService.getStudentsRecords().pipe( map(studentsRecords => { console.log('API Response:', studentsRecords); return { type: actionsList.callStudentsRecordsApiSuccess, payload: studentsRecords } }), catchError((error) => { console.error('Error fetching students records:', error); return of({ type: '[Students API] Students Loaded Error' }); }), )) )); } }
方案2:使用inject()注入(推荐)
这是Angular 14+官方推荐的注入方式,代码更简洁,无需考虑初始化顺序问题:
import { inject, Injectable } from "@angular/core"; import { Actions, createEffect, ofType } from "@ngrx/effects"; import { actionsList } from "./students.actions"; import { catchError, exhaustMap, map, of } from "rxjs"; import { StudentsRecordsService } from "../services/students-records.service"; @Injectable() export class StudentsRecordsEffects { actions$ = inject(Actions); studentsRecordsService = inject(StudentsRecordsService); loadStudentsRecords$ = createEffect(() => this.actions$.pipe( ofType(actionsList.callStudentsRecordsApi), exhaustMap(() => this.studentsRecordsService.getStudentsRecords().pipe( map(studentsRecords => { console.log('API Response:', studentsRecords); return { type: actionsList.callStudentsRecordsApiSuccess, payload: studentsRecords } }), catchError((error) => { console.error('Error fetching students records:', error); return of({ type: '[Students API] Students Loaded Error' }); }), )) )); }
内容的提问来源于stack exchange,提问作者Simone Buscaino
相关产品推荐
相关产品推荐

