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

如何在Ngrx中实现请求时IsLoading控制及执行顺序保证?

解决Ngrx单Action触发Reducer与Effect并控制执行顺序的方案

核心实现思路

Ngrx的设计本身就支持同一个Action同时被Reducer和Effect监听,而且Reducer是同步执行的,Effect是异步执行的,天然就能保证先执行Reducer设置isLoading=true,再触发Effect的异步操作,完全符合你的需求,不需要额外处理顺序问题。

具体代码实现步骤

1. 定义Action

先创建三个Action:触发操作的主Action、请求成功/失败的结束Action:

// actions.ts
import { createAction, props } from '@ngrx/store';
import { YourModel } from './your.model';

// 用户触发的主Action
export const updateObject = createAction(
  '[Your Feature] Update Object',
  props<{ payload: YourModel }>()
);

// 请求成功后触发的Action
export const updateObjectSuccess = createAction(
  '[Your Feature] Update Object Success',
  props<{ payload: YourModel }>()
);

// 请求失败后触发的Action(可选,用于错误处理)
export const updateObjectFailure = createAction(
  '[Your Feature] Update Object Failure',
  props<{ error: any }>()
);

2. Reducer处理状态更新

Reducer同步监听主Action,设置isLoading=true;同时监听成功/失败Action,设置isLoading=false并更新数据:

// reducers.ts
import { createReducer, on } from '@ngrx/store';
import * as YourActions from './actions';
import { initialState, YourState } from './state';

export const yourReducer = createReducer(
  initialState,
  // 主Action触发时,同步设置isLoading为true,可暂存更新的数据
  on(YourActions.updateObject, (state, { payload }) => ({
    ...state,
    isLoading: true,
    // 可选:先在本地显示更新后的数据,后续用服务器返回数据覆盖
    data: payload
  })),
  // 请求成功后,更新数据并关闭loading
  on(YourActions.updateObjectSuccess, (state, { payload }) => ({
    ...state,
    isLoading: false,
    data: payload,
    error: null
  })),
  // 请求失败后,关闭loading并记录错误
  on(YourActions.updateObjectFailure, (state, { error }) => ({
    ...state,
    isLoading: false,
    error: error
  }))
);

3. Effect处理异步请求

Effect监听主Action,执行服务器请求,完成后分发成功/失败Action:

// effects.ts
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import * as YourActions from './actions';
import { YourService } from './your.service';

@Injectable()
export class YourEffects {
  updateObject$ = createEffect(() =>
    this.actions$.pipe(
      ofType(YourActions.updateObject),
      // 取出Action中的数据,调用服务发起请求
      switchMap((action) =>
        this.yourService.saveOrFetchData(action.payload).pipe(
          // 请求成功,分发成功Action
          map((response) => YourActions.updateObjectSuccess({ payload: response })),
          // 请求失败,分发失败Action
          catchError((error) => of(YourActions.updateObjectFailure({ error })))
        )
      )
    )
  );

  constructor(private actions$: Actions, private yourService: YourService) {}
}

4. 组件中使用

组件通过selector获取状态,根据isLoading控制UI阻塞:

// your.component.ts
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { selectYourData, selectIsLoading } from './selectors';
import * as YourActions from './actions';
import { YourModel } from './your.model';

@Component({
  selector: 'app-your',
  template: `
    <div *ngIf="isLoading$ | async" class="loading-overlay">加载中...</div>
    <form (ngSubmit)="onSubmit(formValue)">
      <!-- 表单控件 -->
      <button type="submit" [disabled]="isLoading$ | async">保存</button>
    </form>
  `
})
export class YourComponent {
  isLoading$ = this.store.select(selectIsLoading);
  data$ = this.store.select(selectYourData);

  constructor(private store: Store) {}

  onSubmit(formValue: YourModel) {
    // 只需要分发这一个Action即可完成全流程
    this.store.dispatch(YourActions.updateObject({ payload: formValue }));
  }
}

方案可行性说明

  • Reducer同步优先:分发updateObject Action时,Ngrx会先同步执行Reducer逻辑,立刻将isLoading设为true,组件能瞬间感知并阻塞UI。
  • Effect异步后置:Reducer执行完成后,Effect才会监听该Action并启动异步请求,顺序完全有保障。
  • 单一Action触发:用户只需要触发一个Action,就能完成“开启loading + 发起请求 + 关闭loading”的完整流程,符合你的需求。

可选优化点

  • 乐观更新:Reducer处理updateObject时先更新data字段,让用户立刻看到操作效果,后续用服务器返回数据覆盖,提升体验。
  • 错误恢复:在updateObjectFailure的Reducer逻辑中,可恢复之前的数据状态,避免用户看到错误数据。
  • 加载状态细分:将isLoading设为枚举值(如'idle' | 'saving' | 'fetching'),更精准控制不同操作的UI状态。

内容的提问来源于stack exchange,提问作者emery.noel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:52:29