typescriptreact-hooks

Combine Context Providers in React


I'm building an application with Typescript in React. I've got multiple Context providers. return function in App.tsx looks like this:

    return (
        <>
            <AuthenticationProvider>
                <SubscriptionsProvider>
                    <ResourceProvider>
                        <ResourceAggregatesProvider>
                            <ThemeProvider theme={theme}>
                                <Router>
                                    <main>
                                        <Routes>
                                            ...
                                        </Routes>
                                    </main>
                                </Router>
                            </ThemeProvider>
                        </ResourceAggregatesProvider>
                    </ResourceProvider>
                </SubscriptionsProvider>
            </AuthenticationProvider>
        </>
    )

Now I want to reduce the Providers by outsourcing them to something like an AppContextProvider.tsx so that the return function in App.tsx reduces to something like:

    return (
        <>
            <AppContextProvider> # Contains AuthenticationProvider, SubscriptionsProvider, ResourceProvider and ResourceAggregatesProvider
                <ThemeProvider theme={theme}>
                    <Router>
                        <main>
                            <Routes>
                                ...
                            </Routes>
                        </main>
                    </Router>
                </ThemeProvider>
            </AppContextProvider>
        </>
    )

I tried this tutorial but ended up with the following error:
TS2559: Type '{ children: any; }' has no properties in common with type 'IntrinsicAttributes'. within the CombineComponents.tsx

How is this normally managed in a real environment?


Solution

  • return of App.tsx:

    return (
        <AppContextProvider> # Wraps Context providers
            <Router>
                <main>
                    <Routes>
                        ...
                    </Routes>
                </main>
            </Router>
        </AppContextProvider>
    )
    

    Instead of listing all the context providers in the App.tsx, I keep it clean and have all the providers in a separate AppContextProvider:

    const AppContextProvider: FC<Children> = ({children}) => {
        return (
            <AuthenticationProvider>
                <SubscriptionsProvider>
                    <ResourceProvider>
                        <ResourceAggregatesProvider>
                            <ThemeProvider theme={theme}>
                                {children}
                            </ThemeProvider>
                        </ResourceAggregatesProvider>
                    </ResourceProvider>
                </SubscriptionsProvider>
            </AuthenticationProvider>
        );
    };
    
    export default AppContextProvider;
    

    Children.d.ts:

    export type Children = {
        children?: React.ReactNode
    }