Added beforeEach filter. NEXT: Add it to ResourceReducer

pull/1348/head
Rick Carlino 2019-07-31 08:50:43 -05:00
parent 5c068ad158
commit ff85f5c533
1 changed files with 39 additions and 6 deletions

View File

@ -10,27 +10,55 @@ export interface ActionHandler<State, Payload = unknown> {
}
export function generateReducer<State>(initialState: State) {
/** A function that is passed the state, action and action handler.
* This is useful if you have custom business logic that needs to exit early
* or trigger alternative action handlers. Example: Not triggering
* INIT_RESOURCE when UI is set to "read-only" mode. */
type BeforeEach = (state: State,
action: ReduxAction<unknown>,
handler: ActionHandler<State>) => void;
interface GeneratedReducer extends ActionHandler<State> {
/** Adds action handler for current reducer. */
add: <T>(name: Actions, fn: ActionHandler<State, T>) => GeneratedReducer;
/** Triggered before each call. Give you a chance to bail on execution if
* business logic requires it. */
beforeEach(filter: BeforeEach): GeneratedReducer;
/**Triggered after all calls- useful when you have child reducers that need
* state passed down. */
afterEach(handler: ActionHandler<State>): GeneratedReducer;
beforeFilter(): GeneratedReducer;
}
/** Internal information used by `generateReducer` to manage a reducer.
* This is never exposed publicly. */
interface PrivateStuff {
actionHandlers: ActionHandlerDict;
afterEach: ActionHandler<State>;
filter: BeforeEach;
}
type ActionHandlerDict = Dictionary<ActionHandler<State>>;
const NOOP: ActionHandler<State> = (s) => s;
const priv: PrivateStuff =
({ actionHandlers: {}, afterEach: NOOP });
type ActionHandlerDict = Dictionary<ActionHandler<State>>;
/** Used as a NO-OP when no action handler is found for an action. */
const EMPTY_HANDLER: ActionHandler<State> =
(state, _action) => state;
/** The most simple BeforeFilter. Does not implement any special logic and
* always triggers the action handler. */
const DEFAULT_BEFORE_EACH: BeforeEach =
(state, action, handler) => handler(state, action);
const priv: PrivateStuff = {
actionHandlers: {},
afterEach: EMPTY_HANDLER,
filter: DEFAULT_BEFORE_EACH
};
const reducer: GeneratedReducer =
((state = initialState, action: ReduxAction<unknown>): State => {
// Find the handler in the dictionary, or use the NOOP.
const handler = (priv.actionHandlers[action.type] || NOOP);
const handler = (priv.actionHandlers[action.type] || EMPTY_HANDLER);
// Defensively clone the action and state to avoid accidental mutations.
const clonedState = defensiveClone(state);
@ -53,5 +81,10 @@ export function generateReducer<State>(initialState: State) {
return reducer;
};
reducer.beforeEach = (filter: BeforeEach) => {
priv.filter = filter;
return reducer;
};
return reducer;
}