Skip to content

Instantly share code, notes, and snippets.

@ashaffah
Last active May 29, 2025 14:47
Show Gist options
  • Save ashaffah/54ea83105476c569320364a913a8464f to your computer and use it in GitHub Desktop.
Save ashaffah/54ea83105476c569320364a913a8464f to your computer and use it in GitHub Desktop.
React Provider tree for provider hell
const ProvidersTree = BuildProvidersTree([
[ProviderOne],
[ProviderTwo],
[ProviderThree, {data:data}],
]);
function App(): React.JSX.Element {
// something else..
return (
<ProvidersTree />
);
}
export default App;
import React from "react";
// Define a type for React components that accept props and children
type ComponentWithProps = React.ComponentType<{ children?: React.ReactNode }>;
// Utility type to handle components with or without props e.g BuildProvidersTree([[ExampleProvider]]);
type ComponentsWithProps<TComponents extends readonly ComponentWithProps[]> = {
[K in keyof TComponents]:
| readonly [TComponents[K]]
| readonly [TComponents[K], Partial<React.ComponentProps<TComponents[K]>>];
} & { length: TComponents["length"] };
const BuildProvidersTree = <T extends readonly ComponentWithProps[]>(
componentsWithProps: ComponentsWithProps<T>
) => {
const initialComponent: React.FC<React.PropsWithChildren> = ({
children,
}) => <>{children}</>;
return componentsWithProps.reduce<React.FC<React.PropsWithChildren>>(
(AccumulatedComponents, [Provider, props = {}]) => {
const WrappedComponent: React.FC<React.PropsWithChildren> = ({
children,
}) => (
<AccumulatedComponents>
<Provider {...props}>{children}</Provider>
</AccumulatedComponents>
);
// Safely access displayName or name, with fallback
WrappedComponent.displayName = `Wrapped(${
Provider.displayName || Provider.name || "Component"
})`;
return WrappedComponent;
},
initialComponent
);
};
export default BuildProvidersTree;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment