Meta-reducers in NgRx are a clever tool that lets you intercept and change actions or state before they go to your reducers. They act as enhanced reducers, allowing you to handle important jobs like managing state loading, tracking actions for logs, and solving issues.
-
Definition and Purpose: Meta-reducers wrap other reducers to enhance or modify their behavior. They can be applied to all actions or selectively to specific ones.
-
Usage: Meta-reducers are registered using the
StoreModule.forRootorStoreModule.forFeaturemethods. They also utilize theprovideStatefunction. These meta-reducers receive the current state and action as inputs, allowing them to modify these inputs before passing them on to the next reducer.
How to use
1export function log(reducer: ActionReducer<any>): ActionReducer<any> {2 return function (state, action) {3 console.log('state ->', state);4 console.log('action ->', action);5 return reducer(state, action);6 };7}8
9export const metaReducers: MetaReducer<any>[] = [log];1import { metaReducers } from './meta-reducer';2
3export const appConfig: ApplicationConfig = {4 providers: [5 provideStore(),6 provideState(booksFeature.name, booksFeature.reducer, { metaReducers }),7 provideEffects(BooksEffect),8 provideStoreDevtools({ maxAge: 25, logOnly: !isDevMode() }),9 ],10};1state -> {books: Array(0)}2action -> {type: '[Books Api] Load Books'}3state -> {books: Array(0)}4action -> {type: '[Books Api] Load Books Successful', books: Array(8)}Logger Meta-Reducer
Meta-reducer to log each action dispatched
1export function loggerMetaReducer(reducer: ActionReducer<any>): ActionReducer<any> {2 return (state, action) => {3 console.log('State before:', state);4 console.log('Action:', action);5 const newState = reducer(state, action);6 console.log('State after:', newState);7 return newState;8 };9}10
11export const metaReducers: MetaReducer<any>[] = [loggerMetaReducer];State Rehydration Meta-Reducer
Meta-reducer to rehydrate state from local storage:
1export function rehydrateMetaReducer(reducer: ActionReducer<any>): ActionReducer<any> {2 return (state, action) => {3 const storedState = localStorage.getItem('appState');4 if (storedState) {5 state = JSON.parse(storedState);6 }7 const newState = reducer(state, action);8 localStorage.setItem('appState', JSON.stringify(newState));9 return newState;10 };11}12
13export const metaReducers: MetaReducer<any>[] = [rehydrateMetaReducer];With these meta-reducers, every action in your app is tracked, and the state is saved and restored between uses