import React, { useContext, useMemo } from 'react'; import { AppContext } from './AppContext'; import { DispatchObject } from '../util/types'; import { AppState } from './state'; interface ConnectParams { mapStateToProps?: (state: AppState, props: TOwnProps) => TStateProps; mapDispatchToProps?: TDispatchProps; component: React.ComponentType; } export function connect< TOwnProps = any, TStateProps = any, TDispatchProps = any >({ mapStateToProps = () => ({} as TStateProps), mapDispatchToProps = {} as TDispatchProps, component, }: ConnectParams< TOwnProps, TStateProps, TDispatchProps >): React.FunctionComponent { const Connect = (ownProps: TOwnProps) => { const context = useContext(AppContext); const dispatchFuncs = useMemo(() => { const dispatchFuncs: { [key: string]: any } = {}; if (mapDispatchToProps) { Object.keys(mapDispatchToProps).forEach((key) => { const oldFunc = (mapDispatchToProps as any)[key]; const newFunc = (...args: any) => { const dispatchFunc = oldFunc(...args); if (typeof dispatchFunc === 'object') { context.dispatch(dispatchFunc); } else { const result = dispatchFunc(context.dispatch); if (typeof result === 'object' && result.then) { result.then((dispatchObject?: DispatchObject) => { if (dispatchObject && dispatchObject.type) { context.dispatch(dispatchObject); } }); } } }; dispatchFuncs[key] = newFunc; }); } return dispatchFuncs; // eslint-disable-next-line }, [mapDispatchToProps]); const props = useMemo(() => { return Object.assign( {}, ownProps, mapStateToProps(context.state, ownProps), dispatchFuncs ); // eslint-disable-next-line }, [ownProps, context.state]); return React.createElement(component, props); }; return React.memo(Connect as any); }