diff --git a/lib/context-store.js b/lib/potent-reducer.js similarity index 58% rename from lib/context-store.js rename to lib/potent-reducer.js index 7aa2804..6db2627 100644 --- a/lib/context-store.js +++ b/lib/potent-reducer.js @@ -1,9 +1,13 @@ import React, { createContext, useContext, useMemo, useReducer } from 'react' /** Takes objects that fully define a store and turns it into a more potent reducer */ -export const useReducerStore = storeDef => { - const { reducer = {}, thunks = {}, initialState } = storeDef - const reducerFn = useMemo(() => makeReducerFn(reducer), [reducer]) +export const usePotentReducer = options => { + const { reducer = {}, thunks = {}, initialState } = 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, dispatch), [ thunks, @@ -15,10 +19,10 @@ export const useReducerStore = storeDef => { /** A ReducerStore Factory that uses React.context * Used to make a Store accessible through multiple components */ -export const createStore = storeDef => { +export const createStore = options => { const context = createContext(null) const Provider = ({ children }) => { - const store = useReducerStore(storeDef) + const store = usePotentReducer(options) return React.createElement(context.Provider, { value: store }, children) } const useStore = () => useContext(context) @@ -29,12 +33,16 @@ export const createStore = storeDef => { * @param {Object} reducer: Object definition of a reducer: {: (state, payload) => } * @returns {Function}: Proper reducer */ -function makeReducerFn(reducer) { - return (state, action) => { +function makeReducerFn(reducer, { onUpdate, logging }) { + const noop = state => state + return (prevState, action) => { const { type, ...payload } = action - if (typeof reducer[type] === 'undefined') return state - const newState = reducer[type](state, payload) - return newState + const reducerBranch = reducer[type] || reducer['default'] || noop + const nextState = reducerBranch(prevState, payload) + const stats = { prevState, nextState, action } + typeof onUpdate === 'function' && onUpdate(stats) + if (logging) logger(stats) + return nextState } } @@ -60,3 +68,13 @@ function patchDispatch(dispatch, type) { dispatch({ type, ...action }) } } + +/** 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() +}