Skip to content

Commit

Permalink
chore: use ComposeChildren for composing multiple providers
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtemSBulgakov committed Feb 24, 2024
1 parent d58abff commit 5314937
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 21 deletions.
4 changes: 3 additions & 1 deletion app/providers.tsx → app/_query_provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useState } from "react";

export default function Providers({ children }: { children: React.ReactNode }) {
export default function CustomQueryClientProvider({
children,
}: React.PropsWithChildren) {
const [queryClient] = useState(
() =>
new QueryClient({
Expand Down
44 changes: 26 additions & 18 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Providers from "@/app/providers";
import CustomQueryClientProvider from "@/app/_query_provider";
import ThemedHtml from "@/app/theme";
import Sidebar from "@/components/layout/Sidebar";
import ComposeChildren from "@/components/utils/ComposeChildren";
import GoogleAnalytics from "@/lib/tracking/GoogleAnalytics";
import UserInfoTracker from "@/lib/tracking/UserInfoTracker";
import YandexMetrika from "@/lib/tracking/YandexMetrika";
Expand Down Expand Up @@ -40,31 +41,38 @@ export const viewport: Viewport = {
export default function RootLayout({
children,
modal,
}: {
children: React.ReactNode;
modal: React.ReactNode;
}) {
}: React.PropsWithChildren<{ modal: React.ReactNode }>) {
return (
<ThemedHtml
lang="en"
className={clsx(rubik.variable, fuzzyBubbles.variable)}
>
<head>
{/* Trackers */}
<YandexMetrika />
<GoogleAnalytics />
</head>

<body className="bg-base font-primary text-lg text-text-main">
<Providers>
<noscript className="flex w-full justify-center bg-red-700 p-8">
You need to enable JavaScript to run this app.
</noscript>
<YandexMetrika />
<GoogleAnalytics />
<noscript className="flex w-full justify-center bg-red-700 p-8">
You need to enable JavaScript to run this app.
</noscript>

<ComposeChildren>
{/* Providers */}
<CustomQueryClientProvider />
<UserInfoTracker />

<div className="flex flex-row">
<Sidebar>
<main className="w-full">{children}</main>
</Sidebar>
</div>
{modal}
</Providers>
{/* Content */}
<>
<div className="flex flex-row">
<Sidebar>
<main className="w-full">{children}</main>
</Sidebar>
</div>
{modal}
</>
</ComposeChildren>
</body>
</ThemedHtml>
);
Expand Down
41 changes: 41 additions & 0 deletions components/utils/ComposeChildren.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Children, createElement, isValidElement } from "react";

/**
* Compose providers sequentially inside each other to avoid nesting.
*
* Example:
*
* ```tsx
* <ComposeChildren>
* <ThemeProvider theme={theme} />
* <AuthProvider />
* <QueryClientProvider client={queryClient} />
* {children}
* </ComposeChildren>
* ```
* equals to
* ```tsx
* <ThemeProvider theme={theme}>
* <AuthProvider>
* <QueryClientProvider client={queryClient}>
* {children}
* </QueryClientProvider>
* </AuthProvider>
* </ThemeProvider>
* ```
*/
export default function ComposeChildren({ children }: React.PropsWithChildren) {
const array = Children.toArray(children);
const last = array.pop();
return (
<>
{array.reduceRight(
(child, element) =>
isValidElement(element)
? createElement(element.type, element.props, child)
: child,
last,
)}
</>
);
}
4 changes: 2 additions & 2 deletions lib/tracking/UserInfoTracker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useUsersGetMe } from "@/lib/events";
import { ymUserParams } from "@/lib/tracking/YandexMetrika";
import { useEffect } from "react";

export default function UserInfoTracker() {
export default function UserInfoTracker({ children }: React.PropsWithChildren) {
const { data } = useUsersGetMe();

// Send user info to Yandex Metrika
Expand All @@ -17,5 +17,5 @@ export default function UserInfoTracker() {
}
}, [data]);

return <></>;
return <>{children}</>;
}

0 comments on commit 5314937

Please sign in to comment.