-
-
Save kevinold/e60f6a7ce4a1c23c6972fdecb6b37309 to your computer and use it in GitHub Desktop.
General-purpose reducers for Redux.
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
/** | |
* This gist was inspired by the video course titled "Building React Applications with Idiomatic Redux" | |
* available on Egghead.io by the creator of Redux, Dan Abramov. | |
* | |
* The purpose of this gist is to demonstrate general purpose reducers that can be used via Redux's combineReducers | |
* to compose more complex reducers and therefore maximize code reuse. | |
* | |
* Feedback is more than welcome! | |
* | |
* @author Christoffer Niska <[email protected]> | |
* @link https://egghead.io/courses/building-react-applications-with-idiomatic-redux | |
*/ | |
import uniq from 'lodash/uniq'; | |
import { combineReducers } from 'redux'; | |
/** | |
* Creates a reducer that manages a single value. | |
* | |
* @param {function(state, action)} shouldUpdate | |
* @param {function(state, action)} shouldReset | |
* @param {function(state, action)} getValue | |
* @param {*} defaultValue | |
* @returns {function(state, action)} | |
*/ | |
const createValue = (shouldUpdate = () => true, shouldReset = () => false, getValue = (state, action) => action.payload, defaultValue = null) => | |
(state = defaultValue, action) => { | |
if (shouldReset(state, action)) { | |
return defaultValue; | |
} | |
if (shouldUpdate(state, action)) { | |
return getValue(state, action); | |
} | |
return state; | |
}; | |
/** | |
* Creates a reducer that manages a map. | |
* | |
* @param {function(state, action)} shouldUpdate | |
* @param {function(state, action)} shouldReset | |
* @param {function(state, action)} getValue | |
* @returns {function(state, action)} | |
*/ | |
const createMap = (shouldUpdate = () => true, shouldReset = () => false, getValues = (state, action) => action.payload) => | |
createValue(shouldUpdate, shouldReset, (state, action) => ({ ...state, ...getValues(state, action) }), {}); | |
/** | |
* Creates a reducer that manages a set. | |
* | |
* @param {function(state, action)} shouldUpdate | |
* @param {function(state, action)} shouldReset | |
* @param {function(state, action)} getValue | |
* @returns {function(state, action)} | |
*/ | |
const createSet = (shouldUpdate = () => true, shouldReset = () => false, getValues = (state, action) => action.payload) => | |
createValue(shouldUpdate, shouldReset, (state, action) => uniq([...state, ...getValues(state, action)]), []); | |
/** | |
* Creates a reducer that manages a flag. | |
* | |
* @param {function(state, action)} shouldTurnOn | |
* @param {function(state, action)} shouldTurnOff | |
* @param {bool} defaultValue | |
* @returns {function(state, action)} | |
*/ | |
const createFlag = (shouldTurnOn, shouldTurnOff, defaultValue = false) => | |
(state = defaultValue, action) => { | |
if (shouldTurnOn(state, action)) { | |
return true; | |
} | |
if (shouldTurnOff(state, action)) { | |
return false; | |
} | |
return state; | |
}; | |
/** | |
* Example usage. | |
* | |
* This example assumes that the data is set as a payload property on the action object. | |
* In the real world this might not be the case, in that case use the third parameter to customize this. | |
*/ | |
const UserActions = { | |
FETCH_REQUEST: 'user/FETCH_REQUEST', | |
FETCH_SUCCESS: 'user/FETCH_SUCCESS', | |
FETCH_FAILURE: 'user/FETCH_FAILURE' | |
}; | |
const reducer = combineReducers({ | |
isFetching: createFlag( | |
(state, action) => action.type === UserActions.FETCH_REQUEST, | |
(state, action) => [UserActions.FETCH_SUCCESS, UserActions.FETCH_FAILURE].indexOf(action.type) !== -1 | |
), | |
byId: createMap( | |
(state, action) => action.type === UserActions.FETCH_SUCCESS, | |
(state, action) => action.type === UserActions.FETCH_REQUEST | |
), | |
ids: createSet( | |
(state, action) => action.type === UserActions.FETCH_SUCCESS, | |
(state, action) => action.type === UserActions.FETCH_REQUEST | |
), | |
errorMessage: createValue( | |
(state, action) => action.type === UserActions.FETCH_FAILURE, | |
(state, action) => action.type === UserActions.FETCH_DEPARTMENT | |
) | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment