Skip to content

Instantly share code, notes, and snippets.

@WomB0ComB0
Created January 10, 2025 00:06
Show Gist options
  • Save WomB0ComB0/451a4e7e14e0cfa1c7dc3d4aecf7bf93 to your computer and use it in GitHub Desktop.
Save WomB0ComB0/451a4e7e14e0cfa1c7dc3d4aecf7bf93 to your computer and use it in GitHub Desktop.
A reusable providers component that almost eliminates the need for context API
'use client';
import type { JSXElementConstructor, ReactNode } from 'react';
type InferProps<T> = T extends JSXElementConstructor<infer P> ? P : never;
type ProviderWithProps<T extends JSXElementConstructor<unknown>> = [
T,
Omit<InferProps<T>, 'children'>
];
type InferProviderArray<T extends ReadonlyArray<JSXElementConstructor<unknown>>> = {
[K in keyof T]: ProviderWithProps<T[K]>;
};
type ProvidersProps<T extends JSXElementConstructor<unknown>[]> = {
children: ReactNode;
providers: InferProviderArray<T>;
};
/**
* Component that recursively composes provider components
*/
function ProviderStack<T extends JSXElementConstructor<any>[]>({
providers,
children,
}: ProvidersProps<T>): JSX.Element {
return providers.reduceRight(
(node, [Provider, props]) => <Provider {...props}>{node}</Provider>,
<>{children}</>
);
}
/**
* Provider wrapper component that composes multiple context providers
*/
export function Providers<T extends JSXElementConstructor<any>[]>({
children,
providers,
}: ProvidersProps<T>): JSX.Element {
return <ProviderStack providers={providers} children={children} />;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment