Last active
May 29, 2025 14:47
-
-
Save ashaffah/54ea83105476c569320364a913a8464f to your computer and use it in GitHub Desktop.
React Provider tree for provider hell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const ProvidersTree = BuildProvidersTree([ | |
[ProviderOne], | |
[ProviderTwo], | |
[ProviderThree, {data:data}], | |
]); | |
function App(): React.JSX.Element { | |
// something else.. | |
return ( | |
<ProvidersTree /> | |
); | |
} | |
export default App; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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