From 30aa1e95dc640d866a3faa230e0c804e4ddf2895 Mon Sep 17 00:00:00 2001 From: Alfred Melch Date: Sat, 1 Feb 2020 10:01:18 +0100 Subject: [PATCH] create first draft --- lib/context-reducer.js | 66 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 lib/context-reducer.js diff --git a/lib/context-reducer.js b/lib/context-reducer.js new file mode 100644 index 0000000..70b1a52 --- /dev/null +++ b/lib/context-reducer.js @@ -0,0 +1,66 @@ +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() +}