Last active
March 2, 2018 05:03
-
-
Save v0lkan/595dab12ce81e96f5276f0a436adf0ba to your computer and use it in GitHub Desktop.
Switching Reducer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Put the lib here https://github.com/jsbites/swop/blob/master/index.js — and also create an NPM package with the name
swop
too :)