Skip to content

Instantly share code, notes, and snippets.

@yepitschunked
Created December 17, 2019 02:24
Show Gist options
  • Save yepitschunked/870fae3055cf76c978a974803c76b5e3 to your computer and use it in GitHub Desktop.
Save yepitschunked/870fae3055cf76c978a974803c76b5e3 to your computer and use it in GitHub Desktop.
consume multiple contexts
type ContextValueType<T extends React.Context<unknown>[]> =
| {
[K in keyof T]: T[K] extends React.Context<infer U> ? U : never;
}
| [];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function consumerWrapper<T extends React.Context<any>[]>(...contexts: T) {
return ({
children,
}: {
children: (...contextValues: ContextValueType<T>) => React.ReactElement;
}) =>
// For some reason the spread operator results in a 'Argument of type ContextValueType<T>[number][] is not assignable to parameter of type ContextValueType<T>, but it works with apply.
/* eslint-disable prefer-spread */
contexts.reduceRight(
(memo, type) => (...precedingValues: ContextValueType<T>) => (
<type.Consumer>
{(value) => memo.apply(null, [...precedingValues, value] as ContextValueType<T>)}
</type.Consumer>
),
children,
)();
/* eslint-enable prefer-spread */
}
@yepitschunked
Copy link
Author

Usage:

const Wrapper = consumerWrapper(C1, C2, C3 ...);
<Wrapper>
  {(c1, c2, c3 ...) => ... }
</Wrapper>

Saves you from having to write consumers and render funcs repeatedly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment