Created
November 15, 2018 23:00
-
-
Save masiamj/f23b5ad3adcd7f4f97576224478db9e4 to your computer and use it in GitHub Desktop.
Succinct Redux (Orders)
This file contains 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
/** | |
* orders/index.js | |
* | |
* @desc The key to our succinct redux pattern is to keep our domain action types, reducer, actions, selectors, and data HOCs | |
* in the same file as these functions are inherently coupled | |
*/ | |
/** | |
* @desc Imports | |
*/ | |
import PropTypes from 'prop-types' | |
import { connect } from 'react-redux' | |
import { get, without } from 'lodash-fp' | |
import { createSelector } from 'reselect' | |
/** | |
* @desc Defines the action types to be fired | |
* @desc We always define these as constants to avoid the magic-string problem | |
* @desc We always name our action types using the pattern <application>/<domain>/<ACTION>, to avoid | |
* namespace collisions | |
*/ | |
export const ACTION_TYPES = { | |
ADD: 'internalTool/orders/ADD', | |
REMOVE: 'internalTool/orders/REMOVE', | |
RESET: 'internalTool/orders/RESET', | |
SET: 'internalTool/orders/SET' | |
} | |
/** | |
* @desc Defines the initial state | |
* @desc We always use the `data` key when we store a list of data | |
*/ | |
export const initialState = { | |
data: [] | |
} | |
/** | |
* @desc The reducer for the `orders` store | |
* @desc Some people choose to use abstraction libraries to create reducers; however, | |
* we choose to write plain ES6 code for clarity and debuggability | |
*/ | |
export default (reduxState = initialState, { payload, type}) => { | |
switch (type) { | |
case ACTION_TYPES.ADD: | |
return { | |
...reduxState, | |
data: reduxState.data.concat(payload.item) | |
} | |
case ACTION_TYPES.REMOVE: | |
return { | |
...reduxState, | |
data: without([payload.item], reduxState.data) | |
} | |
case ACTION_TYPES.RESET: | |
return initialState | |
case ACTION_TYPES.SET: | |
return { | |
...reduxState, | |
data: payload.data | |
} | |
default: | |
return reduxState | |
} | |
} | |
/** | |
* @desc Now we being our action creators section | |
*/ | |
export const addOrder = item => ({ type: ACTION_TYPES.ADD, payload: { item } }) | |
export const removeOrder = item => ({ type: ACTION_TYPES.REMOVE, payload: { item } }) | |
export const resetOrders = () => ({ type: ACTION_TYPES.RESET }) | |
export const setOrders = data => ({ type: ACTION_TYPES.SET, payload: { data } }) | |
/** | |
* @desc Now we begin our selectors section | |
*/ | |
const getBranch = reduxState => get('orders', reduxState) | |
export const getOrders = createSelector( | |
getBranch, | |
orders => get('data', orders) | |
) | |
/** | |
* @desc Now we define HOCs that can be applied to components that need the orders data and actions | |
*/ | |
export const withOrders = connect(state => ({ | |
orders: getOrders(state) | |
}, { | |
addOrder, | |
removeOrder, | |
resetOrders, | |
setOrders | |
}) | |
/** | |
* @desc Now we define the prop-type so other components have easy imports without | |
*/ | |
export const OrdersPT = { | |
orders: PropTypes.array.isRequired, | |
addOrder: PropTypes.func.isRequired, | |
removeOrder: PropTypes.func.isRequired, | |
resetOrders: PropTypes.func.isRequired, | |
setOrders: PropTypes.func.isRequired, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment