Skip to content

Instantly share code, notes, and snippets.

@WomB0ComB0
Last active November 18, 2025 01:27
Show Gist options
  • Select an option

  • Save WomB0ComB0/451a4e7e14e0cfa1c7dc3d4aecf7bf93 to your computer and use it in GitHub Desktop.

Select an option

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 { JSX, JSXElementConstructor, ReactNode } from 'react';
/**
* Infers the props from a given React component constructor type.
*
* @template T - A React component constructor.
* @readonly
*/
type InferProps<T> = T extends JSXElementConstructor<infer P> ? P : never;
/**
* Represents a tuple of a Provider component and its props (excluding `children`).
*
* @template T - A React component constructor.
* @readonly
*/
type ProviderWithProps<T extends JSXElementConstructor<unknown>> = [
T,
Omit<InferProps<T>, 'children'>,
];
/**
* Infers an array of ProviderWithProps types from a readonly array of provider constructors.
*
* @template T - An array of React component constructors.
* @readonly
* @see ProviderWithProps
*/
type InferProviderArray<T extends ReadonlyArray<JSXElementConstructor<unknown>>> = {
[K in keyof T]: ProviderWithProps<T[K]>;
};
/**
* Props for provider stack or provider wrapper components, used for composing multiple context providers.
*
* @template T - Array of provider constructors.
* @property {ReactNode} node - The React children to be rendered in the innermost provider.
* @property {InferProviderArray<T>} providers - An array of provider components and their props.
* @readonly
*/
type ProvidersProps<T extends JSXElementConstructor<unknown>[]> = {
node: ReactNode;
providers: InferProviderArray<T>;
};
/**
* Recursively composes multiple React context providers around a children node.
*
* @template T - Type of provider components array.
* @param {ProvidersProps<T>} props - The props containing providers and children.
* @returns {JSX.Element} A React element with the composed providers and children.
* @throws {TypeError} If `providers` is not an array or contains invalid provider types.
* @example
* ```tsx
* <ProviderStack providers={[[SomeProvider, {value: 1}]]}>Content</ProviderStack>
* ```
*/
function ProviderStack<T extends JSXElementConstructor<any>[]>({
providers,
node,
}: ProvidersProps<T>): JSX.Element {
return providers.reduceRight(
(node, [Provider, props]) => <Provider key={Provider.name} {...props}>{node}</Provider>,
<>{node}</>,
);
}
/**
* Composes an array of React context providers around its children node.
* Serves as a wrapper for the application's context composition needs.
*
* @template T - Array of component providers.
* @param {ProvidersProps<T>} props - The props containing providers and children.
* @returns {JSX.Element} A React element wrapped with the composed providers.
* @throws {TypeError} If `providers` is not an array or contains invalid provider definitions.
* @example
* ```tsx
* <Providers providers={[[ThemeProvider, {theme}], [SessionProvider, {session}]]}>
* <App />
* </Providers>
* ```
*/
export function Providers<T extends JSXElementConstructor<any>[]>({
node,
providers,
}: ProvidersProps<T>): JSX.Element {
return <ProviderStack providers={providers} node={node} />;
}
@WomB0ComB0
Copy link
Author

      <Providers
        providers={[
          [<Component>, ?{<...props>}],
        ]}
       >
         {...}
       </Providers>

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