create first draft
This commit is contained in:
parent
dc35932027
commit
30aa1e95dc
66
lib/context-reducer.js
Normal file
66
lib/context-reducer.js
Normal 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()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user