diff --git a/app/providers.tsx b/app/_query_provider.tsx similarity index 81% rename from app/providers.tsx rename to app/_query_provider.tsx index 1ff86a5..11bb85a 100644 --- a/app/providers.tsx +++ b/app/_query_provider.tsx @@ -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({ diff --git a/app/layout.tsx b/app/layout.tsx index d295c98..a60c976 100755 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -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"; @@ -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 ( + + {/* Trackers */} + + + + - - - - + + + + {/* Providers */} + -
- -
{children}
-
-
- {modal} -
+ {/* Content */} + <> +
+ +
{children}
+
+
+ {modal} + +
); diff --git a/components/utils/ComposeChildren.tsx b/components/utils/ComposeChildren.tsx new file mode 100644 index 0000000..1ce8f50 --- /dev/null +++ b/components/utils/ComposeChildren.tsx @@ -0,0 +1,41 @@ +import { Children, createElement, isValidElement } from "react"; + +/** + * Compose providers sequentially inside each other to avoid nesting. + * + * Example: + * + * ```tsx + * + * + * + * + * {children} + * + * ``` + * equals to + * ```tsx + * + * + * + * {children} + * + * + * + * ``` + */ +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, + )} + + ); +} diff --git a/lib/tracking/UserInfoTracker.tsx b/lib/tracking/UserInfoTracker.tsx index b24b1a8..4079756 100644 --- a/lib/tracking/UserInfoTracker.tsx +++ b/lib/tracking/UserInfoTracker.tsx @@ -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 @@ -17,5 +17,5 @@ export default function UserInfoTracker() { } }, [data]); - return <>; + return <>{children}; }