angular - 在 NGRX 中任何动作调度后执行效果
问题描述
我正在使用 NGRX 和 Angular 7。
我有一个仅用于用户设置(用户首选项)的商店
这是一个简短的版本=>
import { Action } from '@ngrx/store';
import * as featureModels from './models';
export enum ActionTypes {
SetSettings = '[SETTINGS] Set Settings',
SetNavigationSettings = '[SETTINGS] Set Navigation Settings',
}
export class SetNavigationSettings implements Action {
public readonly type = ActionTypes.SetNavigationSettings;
constructor(public payload: {settings: Partial<featureModels.INavigationSettings>}) {}
}
export class SetSettings implements Action {
public readonly type = ActionTypes.SetSettings;
constructor(public payload: {settings: featureModels.ISettings}) {}
}
export type Actions = SetNavigationSettings |
SetSettings;
更改任何设置后,我想执行一个效果,它将当前设置存储在本地存储中:
目前,在我的效果中,我只是使用这样的选择器,它会在任何状态更改后触发(所以它工作正常)=>
export class SettingsEffects {
constructor(
private actions$: Actions,
private dataService: SettingsDataService,
private localStorageService: LocalStorageService,
private store$: Store<IAppState>
) {
this.store$.pipe(select(featureSelector.selectSettingsState)).subscribe((settings) => {
//save
});
}
@Effect()
init$ = this.actions$.pipe(
ofType(ROOT_EFFECTS_INIT),
switchMap(action => {
const settings = this.localStorageService.retrieve('settings');
console.log(settings)
if (settings) {
return of(new featureActions.SetSettings({settings}));
} else {
return EMPTY;
}
})
);
但是,这将在初始化时执行,因此在我的 INIT Effect 之前,它将始终用存储初始状态覆盖 localStorage 值。这将使我的 Init 效果仅从本地存储中检索初始状态。
我可以将商店选择放在初始化效果中(并且效果很好)
但我想知道是否有一种方法不使用选择器/订阅,而只使用效果。这样每次用户触发一个动作时,它都会保存。
解决方案
正如官方 NgRx 文档中提到的,您可以考虑使用 MetaReducers。
开发人员可以将 meta-reducer 视为 action->reducer 管道的挂钩。元减速器允许开发人员在调用普通减速器之前预处理操作。
使用meta-reducer
,您可以在每次执行操作时执行代码。如上所述,此代码在调用普通 reducer 之前执行。在您的情况下,要存储新状态(在执行当前操作之后),您应该在调用reducer(state, action)
.
export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
return function (state, action) {
const nextState = reducer(state, action);
console.log('log action', action);
console.log('log state', state);
console.log('log next state', nextState);
// store nextState in local storage
localStorage.setItem('state', JSON.stringify(nextState));
return nextState;
};
}
我准备了一个Stackblitz 演示来说明这个答案。
但是,我可以通过与您分享个人观点来建议您另一种选择吗?事实上,meta-reducer
每个动作都被调用。这可能会导致大量不需要的存储调用。
在这种情况下,我宁愿在每个相关效果中调用另一个特定操作来明确请求状态保存。但很明显,缺点是一些重复的代码,并且有漏接电话的风险。
推荐阅读
- java - 如果我在接口和抽象类中使用相同名称的方法,我无法理解超类、接口和子类之间的关系
- deep-learning - 在训练 GAN 时如何描述这些工件?
- node.js - 在 EventEmitter 的侦听器内部调用时,Socket.io 会延迟发出数据
- python - 我的 Python 代码有问题:IndexError: string index out of range
- google-calendar-api - Google Calendar API - 在某个日期之后更新重复事件
- javascript - 从 3 个数组中的元素的相应索引填充一个新数组
- apache-nifi - Nifi加密变量/属性文件
- c# - 使用 Ionic.Zip.ZipFile 将文件添加到 zip 时出错
- jwt - NestJS - 使用微服务进行 JWT 身份验证
- node.js - Sequelize 不在 AWS lambda 中执行