Created
March 16, 2022 14:05
-
-
Save pfgray/ba89d31faf37f8d55b60b5d43aff1cd0 to your computer and use it in GitHub Desktop.
This file contains 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 * as React from 'react' | |
type Component<Props> = (props: Props) => JSX.Element | |
type ReaderComponent<R, Props> = (env: R) => (props: Props) => JSX.Element | |
/** Combine 2 DI components */ | |
const sequence2W = | |
<R1, R2, Props1, Props2>( | |
DIComp1: ReaderComponent<R1, Props1>, | |
DIComp2: ReaderComponent<R2, Props2>, | |
) => | |
<Props,>( | |
make: ( | |
component1: Component<Props1>, | |
component2: Component<Props2>, | |
) => Component<Props>, | |
): ReaderComponent<R1 & R2, Props> => { | |
return envs => { | |
const component1 = React.useMemo(() => DIComp1(envs), [envs]) | |
const component2 = React.useMemo(() => DIComp2(envs), [envs]) | |
const Component = React.useCallback( | |
(props: Props) => | |
React.createElement(make(component1, component2), props), | |
[component1, component2], | |
) | |
return Component | |
} | |
} | |
/** | |
* Usage Example: | |
*/ | |
// A rudimentary fetch context | |
interface FetchContext { | |
fetch: (url: string) => Promise<unknown> | |
} | |
// A "ReaderComponent" that requires the fetch context | |
const FooDI: ReaderComponent<FetchContext, { foo: string }> = _env => props => { | |
React.useEffect(() => { _env.fetch('/endpoint') }, []) | |
return <div>{props.foo}</div> | |
} | |
// A rudimentary redux context | |
interface ReduxContext { | |
useSelector: <T>(f: (a: any) => T) => T | |
dispatch: (a: any) => void | |
} | |
// A "ReaderComponent" that requires the redux context | |
const BarDI: ReaderComponent<ReduxContext, { bar: string }> = _env => props => { | |
const bar = _env.useSelector(state => state.bar) | |
return <div>{props.bar}</div> | |
} | |
// a combination of Foo and Bar that requires a FetchContext _and_ ReduxContext | |
const FooBarDI: ReaderComponent<FetchContext & ReduxContext, { foo: string }> = | |
sequence2W( | |
FooDI, | |
BarDI, | |
)((Foo, Bar) => props => { | |
return ( | |
<div> | |
<Foo foo={props.foo} /> | |
<Bar bar="bar" /> | |
</div> | |
) | |
}) | |
// inject the contexts to get the component: | |
const FooBar = FooBarDI({} as any) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment