Last active
August 16, 2020 05:04
-
-
Save Nathan-Schwartz/ca762c192192b937d42568df986069f9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {createContext, useReducer} from 'react'; | |
import { Subtract } from 'utility-types'; | |
import type { ReactNode } from 'react'; | |
export default function buildStateManager<ContextState extends {}>(reducer: (ContextState, Object) => ContextState, initialState: ContextState) { | |
const context = createContext<{ state?: ContextState, dispatch?: Function }>(initialState); | |
const { Provider, Consumer } = context; | |
const StateProvider = ({ children }) => { | |
const [state, dispatch] = useReducer(reducer, initialState); | |
return <Provider value={{ state, dispatch }}>{children}</Provider> | |
}; | |
// Consumer will render this component whenever state updates. | |
// This doesn't necessarily mean the new state is useful, so we diff the selected state. | |
class PureMiddle extends React.Component<{ name: string, children: ReactNode, state: Object}> { | |
shouldComponentUpdate(nextProps, nextState) { | |
return nextProps.state !== this.props.state | |
} | |
render() { | |
return this.props.children; | |
} | |
} | |
type InjectedProps = { contextValue: ContextState, contextDispatch: Function }; | |
const connectToState = <Props extends InjectedProps>(mapStateToPropsSelector) => | |
(BaseComponent: React.ComponentType<Props>) => | |
React.memo((props: Subtract<Props, InjectedProps>) => { | |
// console.log('ConsumerWrapper rerenderred'); | |
return ( | |
<Consumer> | |
{({ state, dispatch }) => { | |
// console.log('Consumer FaCC renderred'); | |
const newContextSelection = mapStateToPropsSelector(state) | |
return ( | |
<PureMiddle | |
state={newContextSelection} | |
name={BaseComponent.name} | |
children={ | |
<BaseComponent | |
{...props as Props} | |
contextValue={newContextSelection} | |
contextDispatch={dispatch} | |
/> | |
} | |
/> | |
); | |
}} | |
</Consumer> | |
) | |
}); | |
return { StateProvider, connectToState, context }; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment