create first draft

This commit is contained in:
Alfred Melch 2020-02-01 10:01:18 +01:00
parent dc35932027
commit 30aa1e95dc

66
lib/context-reducer.js Normal file
View File

@ -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 (
<context.Provider value={[store[0], thunks]}>{children}</context.Provider>
)
}
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()
}