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

NGRX Effect调用API后成功动作触发异常问题求助

NGRX Effects 触发异常问题分析与解决

动作定义

export const createSite = createAction(
  '[Site] Create Site',
  props<{ site: SiteRequest }>()
);

export const createSiteSuccess = createAction(
  '[Site] Create Site Success',
  props<{ site: SiteResponse }>()
);

export const createSiteFailed = createAction(
  '[Site] Create Site Failed',
  props<{ error: any }>()
);

Reducer 代码

export const SITES_FEATURE_KEY = 'sites';

export interface State extends EntityState<SiteResponse> {
  selectedId?: string | number;
  loaded: boolean;
  loading: boolean;
  error?: string | null;
}

export interface SitesPartialState {
  readonly [SITES_FEATURE_KEY]: State;
}

export const sitesAdapter: EntityAdapter<SiteResponse> = createEntityAdapter<SiteResponse>();

export const initialState: State = sitesAdapter.getInitialState({
  loaded: false,
  loading: false,
});

const sitesReducer = createReducer(
  initialState,
  on(SitesActions.createSite, (state) => ({ ...state, loaded: false, loading: true, error: null })),
  on(SitesActions.createSiteSuccess, (state, { site }) =>
    sitesAdapter.addOne(site, { ...state, loaded: true, loading: false})
  ),
  on(SitesActions.createSiteFailed, (state, { error }) => ({
    ...state,
    error,
  }))
);

export function reducer(state: State | undefined, action: Action) {
  return sitesReducer(state, action);
}

Effects 代码(原始错误版本)

@Injectable()
export class SiteEffects {
 
  createSite$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SiteActions.createSite),
      exhaustMap((action) => this.siteService.createSite(action.siteRequest)
        .pipe(
          map(site => SiteActions.createSiteSuccess({ site })),
          catchError((error) => of(SiteActions.createSiteFailed({ error }))
        )
      )
    )
  );
 
  createSiteSuccess$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SiteActions.createSiteSuccess),
      tap(() => this.router.navigate['dashboard'])
    ),
    { dispatch: false }
  );

  constructor(
    private actions$: Actions,
    private siteService: SiteService,
    private router: Router,
  ) {}
}

遇到的问题

  • 同时保留createSite$和createSiteSuccess$时,createSite$完全不触发,API调用未执行;
  • 注释createSiteSuccess$后,createSite$正常触发,API返回201状态码及site对象,且reducer成功添加实体,但无法跳转仪表盘;
  • 移除createSiteSuccess$的dispatch: false配置时,createSite$触发且API执行,但会陷入循环(符合预期,故需保留dispatch: false)。

问题原因与修复方案

错误点1:动作属性访问错误

createSite动作定义的props是{ site: SiteRequest },但createSite$中错误访问了action.siteRequest,导致传入siteService.createSite的参数为undefined,直接触发catchError分支分发失败动作。而createSiteSuccess$只监听成功动作,所以看起来createSite$没触发,实际是触发后直接走到错误流程。

错误点2:路由导航写法错误

this.router.navigate['dashboard']是错误写法,navigate是方法,需调用this.router.navigate(['dashboard'])。该错误会抛出异常,中断Effects执行链,也是导致createSite$看起来未触发的原因之一。

错误点3:RxJS操作符括号未闭合

catchError的of(SiteActions.createSiteFailed({ error }))缺少闭合括号,导致代码语法错误,影响整个Effect的编译与执行。

修复后的Effects代码

@Injectable()
export class SiteEffects {
 
  createSite$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SiteActions.createSite),
      exhaustMap((action) => this.siteService.createSite(action.site)
        .pipe(
          map(site => SiteActions.createSiteSuccess({ site })),
          catchError((error) => of(SiteActions.createSiteFailed({ error })))
        )
      )
    )
  );
 
  createSiteSuccess$ = createEffect(() =>
    this.actions$.pipe(
      ofType(SiteActions.createSiteSuccess),
      tap(() => this.router.navigate(['dashboard']))
    ),
    { dispatch: false }
  );

  constructor(
    private actions$: Actions,
    private siteService: SiteService,
    private router: Router,
  ) {}
}

额外检查项

  • 确认SiteService.createSite方法正确接收SiteRequest参数,并返回Observable<SiteResponse>;
  • 确保Effects已在模块中正确注册(如EffectsModule.forRoot([SiteEffects]));
  • 开发模式下查看控制台,排查是否有未捕获的语法或运行时错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:18:04