Skip to content

Instantly share code, notes, and snippets.

@masiamj
Created November 15, 2018 23:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masiamj/f23b5ad3adcd7f4f97576224478db9e4 to your computer and use it in GitHub Desktop.
Save masiamj/f23b5ad3adcd7f4f97576224478db9e4 to your computer and use it in GitHub Desktop.
Succinct Redux (Orders)
/**
* 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