如何在NgRx Effects中修改流载荷后再执行其他Effects?
解决NgRx中在其他Effect执行前统一修改Action载荷的问题
你的代码无法修改原Action载荷的核心原因:
- 设置了
{ dispatch: false },且返回的是修改后的payload而非新Action,原Action会不受影响地继续流向其他监听它的Effect - NgRx中已发出的Action是不可变的,无法直接修改,只能通过拦截转换或重新派发的方式处理
方案一:用Effect拦截原Action并派发增强版Action(支持异步获取Store值)
这种方式适合需要异步从Store中获取值的场景,步骤如下:
- 为每个原Action定义对应的增强版Action(或复用原Action类型,注意避免循环触发)
// 示例:定义增强版Action export const action1Enhanced = createAction( '[Feature] Action1 Enhanced', props<{ payload: OriginalAction1Payload & { storeValue: any; storeValue2: any } }>() ); export const action2Enhanced = createAction( '[Feature] Action2 Enhanced', props<{ payload: OriginalAction2Payload & { storeValue: any; storeValue2: any } }>() ); export const action3Enhanced = createAction( '[Feature] Action3 Enhanced', props<{ payload: OriginalAction3Payload & { storeValue: any; storeValue2: any } }>() );
- 修改你的拦截Effect,返回增强版Action(移除
dispatch: false)
addValuesToPayloadOfActions$ = createEffect(() => { return this.actions$.pipe( ofType(actions.action1, actions.action2, actions.action3), concatLatestFrom(() => [ this.store.pipe(select(getSomeStoreValue)), this.store.pipe(select(getSomeStoreValue2)) ]), map(([action, storeValue, storeValue2]) => { switch (action.type) { case actions.action1.type: return actions.action1Enhanced({ payload: { ...action.payload, storeValue, storeValue2 } }); case actions.action2.type: return actions.action2Enhanced({ payload: { ...action.payload, storeValue, storeValue2 } }); case actions.action3.type: return actions.action3Enhanced({ payload: { ...action.payload, storeValue, storeValue2 } }); default: return action; } }) ); });
- 将原来监听
action1/action2/action3的Effect,改为监听对应的增强版Action即可。
方案二:用Meta-Reducer全局转换Action(仅支持同步获取State值)
Meta-Reducer会在Action到达Reducer和Effect之前执行,无需修改原有Effect的监听逻辑,适合同步获取State值的场景:
- 编写Meta-Reducer函数
import { MetaReducer } from '@ngrx/store'; import { State } from './your-store.model'; import * as actions from './your-actions'; import { getSomeStoreValue, getSomeStoreValue2 } from './your-selectors'; export const payloadEnhancerMetaReducer: MetaReducer<State> = (reducer) => { return (state, action) => { const targetActionTypes = [ actions.action1.type, actions.action2.type, actions.action3.type ]; if (targetActionTypes.includes(action.type)) { // 从当前State中同步获取需要添加的值 const storeValue = getSomeStoreValue(state); const storeValue2 = getSomeStoreValue2(state); // 创建增强后的Action,保留原类型,更新payload const enhancedAction = { ...action, payload: { ...action.payload, storeValue, storeValue2 } }; return reducer(state, enhancedAction); } // 非目标Action直接传递 return reducer(state, action); }; };
- 在Store模块中注册Meta-Reducer
import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { reducers, payloadEnhancerMetaReducer } from './your-store.module'; @NgModule({ imports: [ StoreModule.forRoot(reducers, { metaReducers: [payloadEnhancerMetaReducer] }) ] }) export class AppModule {}
注意事项
- 如果需要异步获取Store中的值(比如依赖异步加载的状态),必须使用方案一,Meta-Reducer仅支持同步操作
- 方案一中若复用原Action类型,需添加过滤逻辑避免Effect循环触发(比如在拦截Effect中添加
filter排除自己派发的Action)
内容的提问来源于stack exchange,提问作者Marek
相关产品推荐
相关产品推荐

