externalize package
This commit is contained in:
parent
5afe62bdcc
commit
d69487b048
@ -1,113 +0,0 @@
|
|||||||
import React, { createContext, useContext, useMemo, useReducer } from 'react'
|
|
||||||
|
|
||||||
/** Takes options that fully define a store and turns it into a more potent reducer */
|
|
||||||
export const usePotentReducer = options => {
|
|
||||||
const { reducer = {}, thunks = {}, initialState } = options
|
|
||||||
const { extState, extDispatch } = options
|
|
||||||
const { onUpdate, logging } = options
|
|
||||||
const reducerFn = useMemo(
|
|
||||||
() => makeReducerFn(reducer, { onUpdate, logging }),
|
|
||||||
[reducer, onUpdate, logging]
|
|
||||||
)
|
|
||||||
const [state, dispatch] = useReducer(reducerFn, initialState)
|
|
||||||
const _thunks = useMemo(() => bindThunks(thunks, extDispatch || dispatch), [
|
|
||||||
thunks,
|
|
||||||
extDispatch
|
|
||||||
])
|
|
||||||
return [extState || state, _thunks]
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Turn a reducer definition object to a function
|
|
||||||
* @param {Object} reducer: Object definition of a reducer: {<type>: (state, payload) => <newState>}
|
|
||||||
* @param {Object} options
|
|
||||||
* @returns {Function}: Proper reducer
|
|
||||||
*/
|
|
||||||
export function makeReducerFn(reducer, options = {}) {
|
|
||||||
const { onUpdate, logging } = options
|
|
||||||
const noop = state => state
|
|
||||||
return (prevState, action) => {
|
|
||||||
const { type } = action
|
|
||||||
const reducerBranch = reducer[type] || reducer['default'] || noop
|
|
||||||
const nextState = reducerBranch(prevState, action)
|
|
||||||
const stats = { prevState, nextState, action }
|
|
||||||
typeof onUpdate === 'function' && onUpdate(stats)
|
|
||||||
if (logging) logger(stats)
|
|
||||||
return nextState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Produces a set of actions that are bound to a specific store
|
|
||||||
* The thunks object can contain action creators and/or thunks.
|
|
||||||
* - Action creators: args => action
|
|
||||||
* are dispatched directly when called
|
|
||||||
* - Thunks args => dispatch => dispatch(action)
|
|
||||||
* are called with dispatch as first argument.
|
|
||||||
* The dispatch function will be patched to insert an action type if not given.
|
|
||||||
* This action type will be the SNAKE_CASE'd action name
|
|
||||||
* @param {Object} thunks
|
|
||||||
* @param {Function} dispatch
|
|
||||||
* @returns {object}
|
|
||||||
*/
|
|
||||||
function bindThunks(thunks, dispatch) {
|
|
||||||
const boundThunks = {}
|
|
||||||
for (let name of Object.keys(thunks)) {
|
|
||||||
const defaultType = camelToSnakeCase(name).toUpperCase()
|
|
||||||
const patchedDispatch = patchDispatch(dispatch, defaultType)
|
|
||||||
boundThunks[name] = (...args) => {
|
|
||||||
const thunk = thunks[name](...args)
|
|
||||||
if (typeof thunk !== 'function') patchedDispatch(thunk)
|
|
||||||
else thunk(patchedDispatch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return boundThunks
|
|
||||||
}
|
|
||||||
|
|
||||||
const camelToSnakeCase = str =>
|
|
||||||
str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)
|
|
||||||
|
|
||||||
/** Returns a dispatch function that fills in a default type if none is given */
|
|
||||||
function patchDispatch(dispatch, type) {
|
|
||||||
return action => {
|
|
||||||
dispatch({ type, ...action })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A ReducerStore Factory that uses React.context
|
|
||||||
* Used to make a Store accessible through multiple components
|
|
||||||
*/
|
|
||||||
export const createStore = initialOptions => {
|
|
||||||
const context = createContext(null)
|
|
||||||
const { Consumer } = context
|
|
||||||
const Provider = ({ children, options }) => {
|
|
||||||
const store = usePotentReducer({ ...initialOptions, ...options })
|
|
||||||
return React.createElement(context.Provider, { value: store }, children)
|
|
||||||
}
|
|
||||||
const useStore = () => useContext(context)
|
|
||||||
const useSelector = selector => {
|
|
||||||
const val = selector(useContext(context)[0])
|
|
||||||
initialOptions.warnOnUndefinedSelect && assertSelectedExists(val)
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
const useDispatch = () => useContext(context)[1]
|
|
||||||
return { Provider, Consumer, useStore, useSelector, useDispatch }
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertSelectedExists(value) {
|
|
||||||
if (typeof value !== 'undefined') return
|
|
||||||
console.warn(`A selector returned undefined.
|
|
||||||
This indicates that you tried to access a state property that does not exist.
|
|
||||||
To turn these messages off use {"warnOnUndefinedSelect": false} in options`)
|
|
||||||
console.groupCollapsed('Trace')
|
|
||||||
console.trace()
|
|
||||||
console.groupEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Log action inspired by redux-logger */
|
|
||||||
const logger = ({ prevState, action, nextState }) => {
|
|
||||||
const css = color => `color: ${color}; font-weight: bold;`
|
|
||||||
console.groupCollapsed(`%c action`, 'color: #9E9E9E', action.type)
|
|
||||||
console.log('%c prevState ', css('#9E9E9E'), prevState)
|
|
||||||
console.log('%c action ', css('#03A9F4'), action)
|
|
||||||
console.log('%c nextState ', css('#4CAF50'), nextState)
|
|
||||||
console.groupEnd()
|
|
||||||
}
|
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -11357,6 +11357,11 @@
|
|||||||
"uniq": "^1.0.1"
|
"uniq": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"potent-reducer": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/potent-reducer/-/potent-reducer-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-dK61EZAspd+paB1+PE/4TjKjJW7Y9bWGi+4qQOqVBF2tD0U6j2lcqvh2dtNpaJgEe0MA4MCioKdTUNzHmq/0Dw=="
|
||||||
|
},
|
||||||
"precinct": {
|
"precinct": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/precinct/-/precinct-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/precinct/-/precinct-6.2.0.tgz",
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"debounce": "^1.2.0",
|
"debounce": "^1.2.0",
|
||||||
"i18next": "^19.1.0",
|
"i18next": "^19.1.0",
|
||||||
|
"potent-reducer": "^0.1.0",
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^16.12.0",
|
||||||
"react-i18next": "^11.3.1",
|
"react-i18next": "^11.3.1",
|
||||||
|
Loading…
Reference in New Issue
Block a user