diff --git a/lib/context-reducer.js b/lib/context-reducer.js
deleted file mode 100644
index 70b1a52..0000000
--- a/lib/context-reducer.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import React, {
- createContext,
- useContext,
- useMemo,
- useRef,
- useReducer
-} from 'react'
-
-function createStore({ reducer = {}, actions = {}, initialState = {} }) {
- const context = createContext(initialState)
- const reducerFn =
- typeof reducer === 'function' ? reducer : makeReducerFn(reducer)
-
- const StoreProvider = ({ children }) => {
- const store = useReducer(reducerFn, initialState)
- const storeRef = useRef(store)
- const thunks = useMemo(() => createThunks(actions, storeRef), [storeRef])
- return (
- {children}
- )
- }
-
- const useStore = selector => {
- const [state, actions] = useContext(context)
- return typeof selector === 'function'
- ? selector(state, actions)
- : [state, actions]
- }
-
- return [StoreProvider, useStore]
-}
-
-export default createStore
-
-/** Returns a set of actions that are bound to the store */
-function createThunks(actions, storeRef) {
- const [state, dispatch] = storeRef.current
- const thunks = {}
- for (let name of Object.keys(actions)) {
- thunks[name] = (...args) =>
- actions[name](...args)({
- dispatch,
- state,
- type: camelToSnakeCase(name).toUpperCase()
- })
- }
- return thunks
-}
-
-function makeReducerFn(reducerObj) {
- return (state, action) => {
- const { type, ...payload } = action
- if (typeof reducerObj[type] === 'undefined') return state
- const newState = reducerObj[type](state, payload)
- return newState
- }
-}
-
-const camelToSnakeCase = str =>
- str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)
-
-const [Provider, useStore] = createStore({ reducer: {}, actions: {} })
-
-export const MyConponent = () => {
- const [state, actions] = useStore()
-}
diff --git a/lib/context-store.js b/lib/context-store.js
new file mode 100644
index 0000000..38ff300
--- /dev/null
+++ b/lib/context-store.js
@@ -0,0 +1,62 @@
+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])
+ const [state, dispatch] = useReducer(reducerFn, initialState)
+ const _thunks = useMemo(() => bindThunks(thunks, dispatch), [
+ thunks,
+ dispatch
+ ])
+ return [state, _thunks]
+}
+
+/** A ReducerStore Factory that uses React.context
+ * Used to make a Store accessible through multiple components
+ */
+export const createStore = storeDef => {
+ const context = createContext(null)
+ const Provider = ({ children }) => {
+ const store = useReducerStore(storeDef)
+ return {children}
+ }
+ const useStore = () => useContext(context)
+ return { Provider, Consumer: context.Consumer, useStore }
+}
+
+/** Turn a reducer definition object to a function
+ * @param {Object} reducer: Object definition of a reducer: {: (state, payload) => }
+ * @returns {Function}: Proper reducer
+ */
+function makeReducerFn(reducer) {
+ return (state, action) => {
+ const { type, ...payload } = action
+ if (typeof reducer[type] === 'undefined') return state
+ const newState = reducer[type](state, payload)
+ return newState
+ }
+}
+
+/** Returns a set of actions that are bound to the store
+ * @param {Object} actions: {: payload => ({dispatch, type}) => }
+ */
+function bindThunks(thunks, dispatch) {
+ const _thunks = {}
+ for (let name of Object.keys(thunks)) {
+ const defaultType = camelToSnakeCase(name).toUpperCase()
+ _thunks[name] = (...args) =>
+ thunks[name](...args)(patchDispatch(dispatch, defaultType))
+ }
+ return _thunks
+}
+
+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 })
+ }
+}