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

Ngrx Effects:在switchMap中条件返回Action而非HTTP响应

在NgRx Effects中实现缓存逻辑:根据条件返回Action或HTTP请求

我来帮你搞定这个缓存需求!考虑到你用的是Angular 5,对应的NgRx版本应该是4.x左右,所以我会用适配旧版API的写法来给你演示。核心思路就是先从Store里读取缓存状态,根据缓存是否有效来决定直接返回成功Action还是发起HTTP请求。

核心步骤拆解

    1. 在Effect中通过withLatestFrom操作符,获取当前Store里已缓存的合作伙伴数据
    1. 在switchMap里做分支判断:如果缓存存在且有效,直接返回RequestPartnersSuccess动作;如果没有缓存,才调用服务发起HTTP请求
    1. 请求成功/失败时,依旧映射到对应的Success/Fail动作

具体代码实现

第一步:定义动作(Actions)

先确保你的动作类是按NgRx 4.x的方式定义的:

import { Action } from '@ngrx/store';
import { Partner } from './partner.model';

// 动作类型枚举
export enum PartnersActionTypes {
  REQUEST_PARTNERS = '[Partners] Request Partners',
  REQUEST_PARTNERS_SUCCESS = '[Partners] Request Partners Success',
  REQUEST_PARTNERS_FAIL = '[Partners] Request Partners Fail'
}

// 请求动作
export class RequestPartners implements Action {
  readonly type = PartnersActionTypes.REQUEST_PARTNERS;
}

// 请求成功动作
export class RequestPartnersSuccess implements Action {
  readonly type = PartnersActionTypes.REQUEST_PARTNERS_SUCCESS;
  constructor(public payload: Partner[]) {}
}

// 请求失败动作
export class RequestPartnersFail implements Action {
  readonly type = PartnersActionTypes.REQUEST_PARTNERS_FAIL;
  constructor(public payload: any) {}
}

// 导出动作联合类型
export type PartnersActions = RequestPartners | RequestPartnersSuccess | RequestPartnersFail;

第二步:定义状态结构(Reducer)

在Reducer里要包含标记缓存状态的字段,比如loaded(是否已加载过数据)、data(缓存的列表数据):

import { PartnersActions, PartnersActionTypes } from './partners.actions';
import { Partner } from './partner.model';

export interface PartnersState {
  data: Partner[];
  loaded: boolean; // 标记是否已有缓存数据
  loading: boolean; // 标记是否正在请求
  error: any;
}

// 初始状态
const initialState: PartnersState = {
  data: [],
  loaded: false,
  loading: false,
  error: null
};

// Reducer函数
export function partnersReducer(state = initialState, action: PartnersActions): PartnersState {
  switch (action.type) {
    case PartnersActionTypes.REQUEST_PARTNERS:
      return {
        ...state,
        loading: true,
        error: null
      };
    case PartnersActionTypes.REQUEST_PARTNERS_SUCCESS:
      return {
        ...state,
        data: action.payload,
        loaded: true,
        loading: false
      };
    case PartnersActionTypes.REQUEST_PARTNERS_FAIL:
      return {
        ...state,
        error: action.payload,
        loading: false
      };
    default:
      return state;
  }
}

// 定义选择器,方便在Effect中获取状态
export const getPartnersState = (state: { partners: PartnersState }) => state.partners;

第三步:实现带缓存逻辑的Effect

这是核心部分,在Effect里加入缓存判断:

import { Injectable } from '@angular/core';
import { Actions, Effect } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { of } from 'rxjs';
import { switchMap, withLatestFrom, map, catchError } from 'rxjs/operators';
import { PartnersService } from './partners.service';
import * as PartnersActions from './partners.actions';
import * as fromRoot from '../reducers';

@Injectable()
export class PartnersEffects {
  @Effect()
  loadPartners$ = this.actions$.pipe(
    // 监听请求合作伙伴的动作
    ofType(PartnersActions.PartnersActionTypes.REQUEST_PARTNERS),
    // 同时获取当前Store里的合作伙伴状态
    withLatestFrom(this.store.select(fromRoot.getPartnersState)),
    switchMap(([action, partnersState]) => {
      // 先判断是否已有有效缓存:loaded为true且数据不为空
      if (partnersState.loaded && partnersState.data.length > 0) {
        // 缓存存在,直接返回成功动作,传入缓存数据
        return of(new PartnersActions.RequestPartnersSuccess(partnersState.data));
      } else {
        // 缓存不存在,发起HTTP请求
        return this.partnersService.getPartners().pipe(
          // 请求成功,映射到成功动作
          map(data => new PartnersActions.RequestPartnersSuccess(data)),
          // 请求失败,映射到失败动作
          catchError(error => of(new PartnersActions.RequestPartnersFail(error)))
        );
      }
    })
  );

  constructor(
    private actions$: Actions,
    private store: Store<fromRoot.State>,
    private partnersService: PartnersService
  ) {}
}

额外优化建议

  • 避免重复请求:如果页面上多次触发REQUEST_PARTNERS动作,可以在switchMap里先判断partnersState.loading是否为true,如果是就返回EMPTY(需要导入EMPTY from rxjs),防止同时发起多个请求
  • 缓存过期处理:如果需要缓存自动过期,可以在PartnersState里加lastUpdated字段,记录最后一次请求的时间,在判断缓存时对比当前时间和lastUpdated的差值,超过设定时间就重新请求

这样当用户查看条目后返回主列表时,只要缓存存在且有效,就会直接用Store里的缓存数据,不用再发起HTTP请求啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:37:27