Skip to content

Instantly share code, notes, and snippets.

@viclm
Created August 31, 2020 06:00
Show Gist options
  • Save viclm/98ded16afc1c44bde5c0fd4ab46ae016 to your computer and use it in GitHub Desktop.
Save viclm/98ded16afc1c44bde5c0fd4ab46ae016 to your computer and use it in GitHub Desktop.
import React, { useReducer } from 'react'
import hoistNonReactStatics from 'hoist-non-react-statics'
interface Reducer {
(state, action): any
hook
host
}
function reducerx(isProvide: boolean, ...reducers: Reducer[]) {
return (Component: React.ComponentType) => {
function connect(props, ref) {
const reducerHooks = new WeakMap()
const reducerStates = {}
for (let reducer of reducers) {
let hook
if (reducer.hook && reducer.host !== Component) {
hook = reducer.hook
}
else {
hook = useReducer(reducer, undefined, () => reducer(undefined, {}))
if (isProvide) {
reducer.hook = hook
reducer.host = Component
}
}
reducerHooks.set(hook[0], hook)
reducerStates[reducer.name] = hook[0]
}
const dispatch = (state, action) => {
const hook = reducerHooks.get(state)
if (hook) {
const [ state, dispatch ] = hook
if (typeof action === 'function') {
return action(dispatch, state)
}
return dispatch(action)
}
throw new Error(`reducer(${state}) is not initialized`)
}
return React.createElement(Component, { ...props, ...reducerStates, ref, dispatch })
}
hoistNonReactStatics(connect, Component)
return React.forwardRef(connect)
}
}
export const provide = reducerx.bind(null, true)
export const connect = reducerx.bind(null, false)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment