我正在使用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效果之前,它将始终使用存储初始状态覆盖localStorage值。这将使我的Init效果仅从本地存储中检索初始状态。
我可以将商店选择放到Init Effect内(并且效果很好)
但是我想知道是否有一种方法不使用选择器/订阅,而只是使用效果。这样,每次用户触发操作时,它就会保存。
答案 0 :(得分:1)
如official NgRx docs中所述,您可以考虑使用MetaReducers。
开发人员可以将meta-reducers看作是action-> reduceer管道的钩子。元归约器使开发人员可以在调用常规归约器之前对操作进行预处理。
使用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 demo来说明这个答案。
但是,我是否可以通过与您分享个人观点来建议您其他选择?实际上,每个动作都会调用meta-reducer
。这可能会导致大量不必要的存储调用。
在这种情况下,我宁愿在每个相关效果中调用另一个特定操作来显式请求状态保存。 但是很明显,缺点是一些重复的代码,并且有错过接听电话的风险。