Skip to content

Instantly share code, notes, and snippets.

@pfgray
Created March 16, 2022 14:05
Show Gist options
  • Save pfgray/ba89d31faf37f8d55b60b5d43aff1cd0 to your computer and use it in GitHub Desktop.
Save pfgray/ba89d31faf37f8d55b60b5d43aff1cd0 to your computer and use it in GitHub Desktop.
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