Skip to content

Instantly share code, notes, and snippets.

@v0lkan
Last active March 2, 2018 05:03
Show Gist options
  • Save v0lkan/595dab12ce81e96f5276f0a436adf0ba to your computer and use it in GitHub Desktop.
Save v0lkan/595dab12ce81e96f5276f0a436adf0ba to your computer and use it in GitHub Desktop.
Switching Reducer
// I find myself using this utility function frequently.
// I don’t know if this pattern has a name, yet I’d like
// to call it the “switching reducer”.
// Here’s how you define it:
// ########################
// The Library
// ########################
import type {
Reducer, Action
} from 'jedi-types';
const identity = (x) => x;
const swop = (
reducers: {[key: string]: Reducer},
initialState: () => any = () => ({}),
identityReducer: Reducer
) => (
state: {} = (initialState || identity)(),
{ type, payload }: Action
) => (
reducers[type] || identityReducer || identity
)(state, { type, payload });
// This `swop` function is the switching reducer creator.
export {
swop
};
// ########################
// Type Definitions
// ########################
// Where the types are nothing fancy…
declare module 'jedi-types' {
declare type Reducer = (state: any, action: any) => any;
declare type Action = {
type: string,
payload: any
}
}
// I just explicitly require the actions to have a “payload”
// to make them kind-of Flux-compatible.
// Though other than that, I don’t do any strict type checking.
// ########################
// Usage Example
// ########################
import { fromJS as makeImmutable } from 'immutable';
import type { Action } from 'jedi-types';
import {
JEDI_GOALS_FETCH_STARTED,
JEDI_GOALS_FETCH_DONE,
JEDI_GOALS_FETCH_ERROR
} from 'jedi-constants';
import {
swop
} from 'jedi-lib';
// Just in case your identity transformation is more complicated than x => x
const identityReducer = (state = {}, { type, payload }) => {
void type;
void payload;
return state;
};
const goalsFetchStarted = (state = {}, { type, payload }) => {
void type;
void payload;
return state;
};
const goalsFetchError = (state = {}, { type, payload }) => {
void type;
void payload;
return state;
};
const goalsFetchDone = (state = {}, { type, payload }) => {
void type;
void state;
return makeImmutable(payload);
};
const initialState = () => ({ uninitialized: true });
const reducers = {
[JEDI_GOALS_FETCH_STARTED]: goalsFetchStarted,
[JEDI_GOALS_FETCH_DONE]: goalsFetchDone,
[JEDI_GOALS_FETCH_ERROR]: goalsFetchError
};
// This will create a root reducer that switches between the above reducers
// based on the action type, and default to the identity reducer that you
// provide if no action matches.
export default swop(reducers, initialState, identityReducer);
// The last two arguments are optional. So if no special transformation is needed,
// and if you are okay with a `{}` initial state, then you can
// simply export this:
export default swop(reducers);
// Or alternatively…
export default swop({
[JEDI_GOALS_FETCH_STARTED]: goalsFetchStarted,
[JEDI_GOALS_FETCH_DONE]: goalsFetchDone,
[JEDI_GOALS_FETCH_ERROR]: goalsFetchError
});
@v0lkan
Copy link
Author

v0lkan commented Mar 2, 2018

Put the lib here https://github.com/jsbites/swop/blob/master/index.js — and also create an NPM package with the name swop too :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment