Angular添加provideEffects触发Object.defineProperty错误,移除后Effects失效
问题描述
在Angular项目中配置provideEffects(AuthEffects)时触发Object.defineProperty called on non-object错误,错误栈如下:
at Function.defineProperty (<anonymous>) at Module.createEffect (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/.angular/cache/18.2.4/vite/deps_ssr/@ngrx_effects.js:50:10) at _AuthEffects.<instance_members_initializer> (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/src/app/auth/state/auth.effects.ts:13:12) at new _AuthEffects (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/src/app/auth/state/auth.effects.ts:30:3) at map (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/src/app/auth/state/auth.effects.ts:30:101) at eval (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/.angular/cache/18.2.4/vite/deps_ssr/chunk-S4UJ36BC.js:4456:35) at runInInjectorProfilerContext (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/.angular/cache/18.2.4/vite/deps_ssr/chunk-S4UJ36BC.js:3058:5) at R3Injector.hydrate (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/.angular/cache/18.2.4/vite/deps_ssr/chunk-S4UJ36BC.js:4455:11) at R3Injector.get (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/.angular/cache/18.2.4/vite/deps_ssr/chunk-S4UJ36BC.js:4345:23) at injectInjectorOnly (/Users/stefanoantonetti/WebstormProjects/ngrx-counter-a17/.angular/cache/18.2.4/vite/deps_ssr/chunk-S4UJ36BC.js:3190:36
移除该配置后,auth.effects.ts中的登录Effect无法发起API请求。
相关代码
AuthEffects类
import {Injectable} from "@angular/core"; import {Actions, createEffect, ofType} from "@ngrx/effects"; import {AuthService} from "../services/auth.service"; import {Router} from "@angular/router"; import {loginFailure, loginStart, loginSuccess} from "./auth.actions"; import {catchError, exhaustMap, map, of, tap} from "rxjs"; import {AuthResponse} from "../../models/auth-response.model"; @Injectable() export class AuthEffects { login$ = createEffect(() => { return this.actions$?.pipe( ofType(loginStart), tap(action => console.log('Effetto login innescato', action)), exhaustMap((action) => this.authService.login(action.email, action.password).pipe( map((authResponse: AuthResponse) => { console.log(authResponse) this.router.navigate(['home']).then() return loginSuccess() }), catchError(() => of(loginFailure())) ) ) ); }); constructor(private actions$: Actions, private authService: AuthService, private router: Router) {} }
app.config.ts配置
import {ApplicationConfig, isDevMode, provideZoneChangeDetection} from "@angular/core"; import {provideRouter} from "@angular/router"; import {routes} from "./app.routes"; import {provideClientHydration} from "@angular/platform-browser"; import {provideHttpClient, withFetch} from "@angular/common/http"; import {provideStore} from "@ngrx/store"; import {counterReducer} from "./counter/state/counter.reducer"; import {postsReducer} from "./posts/state/posts.reducer"; import {authReducer} from "./auth/state/auth.reducer"; import {provideEffects} from "@ngrx/effects"; import {AuthEffects} from "./auth/state/auth.effects"; import {provideStoreDevtools} from "@ngrx/store-devtools"; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideClientHydration(), provideHttpClient(withFetch()), provideStore({ counter: counterReducer, posts: postsReducer, auth: authReducer, }), provideEffects(AuthEffects), provideStoreDevtools({ maxAge: 25, logOnly: !isDevMode() }) ] };
解决方法
错误核心原因是Effect初始化时返回了undefined:你在createEffect的工厂函数中使用了可选链this.actions$?.pipe(),当this.actions$还未完成注入时,可选链会返回undefined,而NgRx Effects要求createEffect必须返回有效的Observable流。
修复步骤
- 移除可选链操作符:将
this.actions$?.pipe()改为this.actions$.pipe()。Angular的依赖注入会确保Actions服务在Effect实例化时已完成注入,无需担心this.actions$为null/undefined。 - 保持返回Observable流:确保
createEffect的工厂函数始终返回一个Observable,而非undefined。
修改后的login$ Effect代码:
login$ = createEffect(() => { return this.actions$.pipe( ofType(loginStart), tap(action => console.log('Effetto login innescato', action)), exhaustMap((action) => this.authService.login(action.email, action.password).pipe( map((authResponse: AuthResponse) => { console.log(authResponse) return loginSuccess() }), tap(() => this.router.navigate(['home'])), catchError(() => of(loginFailure())) ) ) ); });
额外优化建议
将router.navigate移到tap操作符中,避免在map里处理副作用,符合NgRx“纯转换+副作用分离”的最佳实践。
内容的提问来源于stack exchange,提问作者Stefano Antonetti
相关产品推荐
相关产品推荐

