Reputation: 23277
I've added into my IStore
a transaction
concept. It straightforwardly stands for providing a way to store into my IStore
which pending operations keep pending. When they are completed, they are removed:
export interface IStore {
user: IUser;
txs: ITxRedux;
}
All my reducers are like:
* reducer name: `'OPERATION'`
* success reducer name: `'OPERATION_SUCCESS'`
* failed reducer name: `'OPERATION_FAILED'`
Some of these reducers (only those need a http request) are captured using @Effects
:
@Effect({ dispatch: true })
userLogin$: Observable<Action> = this._actions$
.ofType('USER_LOGIN')
.switchMap((action: Action) =>
{
....
});
Currently, my effects have this pattern:
return make_http_call
.map(_ => ({type: 'OPERATION_SUCCESS'}, payload: {...}))
.catch(_ => ({type: 'OPERATION_FAILED'}, payload: {...}));
So, I'd like to get a way by adding or removing a "transaction"
into my IStore.txs
each time an effect is called or completed. When I say "add a transaction into my IStore.txs"
I mean to call transaction
reducers:
public static ADD_TX = `ADD_TX`;
private static addTx(txsRdx: ITxRedux, type, payload: ITx) {
const tx = payload;
return {
ids: [ ...txsRdx.ids, tx.id ],
entities: Object.assign({}, txsRdx.entities, {[tx.id]: tx}),
};
}
public static REMOVE_TX = `REMOVE_TX`;
private static removeTx(txsRdx: ITxRedux, type, payload) {
const tx: ITx = payload;
var entitiesTmp = {...txsRdx.entities};
delete entitiesTmp[tx.id];
return {
ids: txsRdx.ids.filter(id => tx.id != id),
entities: entitiesTmp
};
}
I've listen to talk a bit about meta-reducers, but I don't quite whether they are going to be able to get my goal.
Is there any way to get it using a elegant way?
Upvotes: 2
Views: 1409
Reputation: 12735
Late reply, but you might find this post useful. The classic example (taken mostly from that post) is to log each action/state change by means of a logging meta-reducer:
export function logging(reducer) {
return function loggingReducer(state, action) {
console.group(action.type);
// invoke following, "wrapped" reducer in the chain
const nextState = reducer(state, action);
console.log(`%c prev state`, `color: #9E9E9E`, state);
console.log(`%c action`, `color: #03A9F4`, action);
console.log(`%c next state`, `color: #4CAF50`, nextState);
console.groupEnd();
// return wrapped reducer output
return nextState;
};
}
In main app module, you compose the new logging
reducer factory with the usual combineReducers
reducer factory:
const appReducer = compose(logging, combineReducers)(reducers);
//...
StoreModule.provideStore(appReducer),
Just watchout for setting up StoreModule
and global app reducer, as that syntax has changed in recent ngrx versions since that blog post.
On a side note, if you're looking for some inspiration on implementing a meta-reducer to catch and invoke remote API calls, you might want to have a look at an equivalent, already-made middleware for Redux, as redux-api-middleware. HTH
Upvotes: 2