Next.js & Ant Design - Custom ThemedLayoutV2 not working

Hi, I tried to swizzle the ThemedLayout as I need to edit the Sider. But if I follow the documentation: src/app/layout.tsx
...
<Refine ...>
<ThemedLayoutV2 ... />
</Refine>
...
...
<Refine ...>
<ThemedLayoutV2 ... />
</Refine>
...
then I was getting errors that I can't use hooks in a server component. So I created client component refine-context.tsx:
"use client";
...
export const RefineContext = ({ themeMode, children }: PropsWithChildren<Props>) => {
<AntdRegistry>
<ContextProvider>
...
<Refine ...>
<ThemedLayoutV2 ...>
{children}
</ThemedLayoutV2>
</Refine>
</ContextProvider>
</AntdRegistry>
"use client";
...
export const RefineContext = ({ themeMode, children }: PropsWithChildren<Props>) => {
<AntdRegistry>
<ContextProvider>
...
<Refine ...>
<ThemedLayoutV2 ...>
{children}
</ThemedLayoutV2>
</Refine>
</ContextProvider>
</AntdRegistry>
and src/app/layout.tsx:
...
return (
<html lang={locale}>
<body>
<Suspense>
<NextIntlClientProvider locale={locale} messages={messages}>
<RefineContext themeMode={theme?.value}>{children}</RefineContext>
</NextIntlClientProvider>
</Suspense>
</body>
</html>
);
...
return (
<html lang={locale}>
<body>
<Suspense>
<NextIntlClientProvider locale={locale} messages={messages}>
<RefineContext themeMode={theme?.value}>{children}</RefineContext>
</NextIntlClientProvider>
</Suspense>
</body>
</html>
);
Then I end up with "duplicate" layout (the customized layout is correct, but then I am getting the default one inside the customized one..) Does anyone know how to sort that out properly? Thank you in advance!
No description
4 Replies
kapa.ai
kapa.ai3w ago
Hi @Jakub. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the information provided in the knowledge sources, I can offer some guidance on using the ThemedLayoutV2 component with Next.js and Ant Design in refine. However, the specific issue you're encountering with duplicate layouts is not directly addressed in the provided documentation. Let me explain the recommended approach and suggest some potential solutions: 1. Using ThemedLayoutV2 in Next.js: The recommended way to use ThemedLayoutV2 in a Next.js app with refine is slightly different from what you've implemented. According to the Next.js usage documentation, you should structure your app like this:
// pages/_app.tsx
import React from "react";
import { Refine } from "@refinedev/core";
import { RefineThemes, ThemedLayoutV2, useNotificationProvider } from "@refinedev/antd";
import { App as AntdApp, ConfigProvider } from "antd";

function App({ Component, pageProps }: AppProps) {
return (
<ConfigProvider theme={RefineThemes.Blue}>
<AntdApp>
<Refine
// ... other Refine configurations
>
<ThemedLayoutV2>
<Component {...pageProps} />
</ThemedLayoutV2>
</Refine>
</AntdApp>
</ConfigProvider>
);
}

export default App;
// pages/_app.tsx
import React from "react";
import { Refine } from "@refinedev/core";
import { RefineThemes, ThemedLayoutV2, useNotificationProvider } from "@refinedev/antd";
import { App as AntdApp, ConfigProvider } from "antd";

function App({ Component, pageProps }: AppProps) {
return (
<ConfigProvider theme={RefineThemes.Blue}>
<AntdApp>
<Refine
// ... other Refine configurations
>
<ThemedLayoutV2>
<Component {...pageProps} />
</ThemedLayoutV2>
</Refine>
</AntdApp>
</ConfigProvider>
);
}

export default App;
2. Customizing ThemedLayoutV2: If you need to customize the Sider component, you can use the swizzle feature as mentioned in the Customizing with swizzle documentation. After swizzling, you can modify the generated components in your src/components/themedLayout directory. 3. Server Component Issue: The error you're getting about not being able to use hooks in a server component is likely because Next.js 13+ uses React Server Components by default. To resolve this, you can create a client component wrapper as you did, but you might need to adjust where you place the ThemedLayoutV2. 4. Potential Solution: Instead of wrapping your entire app with ThemedLayoutV2, try using it in your page components or in a layout component that wraps your pages. Here's a potential structure:
// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<RefineContext>{children}</RefineContext>
</body>
</html>
);
}

// app/(refine)/layout.tsx
"use client";

import { ThemedLayoutV2 } from "@refinedev/antd";

export default function RefineLayout({ children }) {
return <ThemedLayoutV2>{children}</ThemedLayoutV2>;
}

// app/(refine)/products/page.tsx
"use client";

export default function ProductsPage() {
// Your page content
}
// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<RefineContext>{children}</RefineContext>
</body>
</html>
);
}

// app/(refine)/layout.tsx
"use client";

import { ThemedLayoutV2 } from "@refinedev/antd";

export default function RefineLayout({ children }) {
return <ThemedLayoutV2>{children}</ThemedLayoutV2>;
}

// app/(refine)/products/page.tsx
"use client";

export default function ProductsPage() {
// Your page content
}
This structure separates the Refine context from the themed layout, which might help avoid the duplicate layout issue you're experiencing. If you're still encountering issues after trying these suggestions, it might be helpful to check the official refine GitHub repository for any open issues related to Next.js 13+ and ThemedLayoutV2, or consider opening a new issue with your specific use case. Remember, when customizing the layout, you can pass custom components to ThemedLayoutV2 as props, as shown in the usage documentation:
<ThemedLayoutV2
Header={ThemedHeaderV2}
Sider={ThemedSiderV2}
Title={ThemedTitleV2}
>
{/* Your content */}
</ThemedLayoutV2>
<ThemedLayoutV2
Header={ThemedHeaderV2}
Sider={ThemedSiderV2}
Title={ThemedTitleV2}
>
{/* Your content */}
</ThemedLayoutV2>
This allows you to customize individual parts of the layout without duplicating the entire structure. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@1212152033214464112> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
inland-turquoise
inland-turquoiseOP3w ago
For anybody else looking for the solution. Use basically the solutions from 4. Or you can simply pass the Sider component to the default <ThemedLayoutV2> from @refinedev/antd. So your e.g. src/app/blog-posts/layout.tsx would look like this:
import { Header } from "@components/header";
// import { ThemedLayoutV2 } from "@components/layout/index"; <<-- you can use your own layout
import { ThemedLayoutV2 } from "@refinedev/antd";
import { redirect } from "next/navigation";
import React from "react";
import { ThemedSiderV2 } from "@components/layout/sider";

export default async function Layout({ children }: React.PropsWithChildren) {
const data = await getData();

if (!data.authenticated) {
return redirect(data?.redirectTo || "/login");
}

return <ThemedLayoutV2 Header={Header} Sider={ThemedSiderV2}>{children}</ThemedLayoutV2>; // or just pass your custom Sider to the default layout
}
... // getData()...
import { Header } from "@components/header";
// import { ThemedLayoutV2 } from "@components/layout/index"; <<-- you can use your own layout
import { ThemedLayoutV2 } from "@refinedev/antd";
import { redirect } from "next/navigation";
import React from "react";
import { ThemedSiderV2 } from "@components/layout/sider";

export default async function Layout({ children }: React.PropsWithChildren) {
const data = await getData();

if (!data.authenticated) {
return redirect(data?.redirectTo || "/login");
}

return <ThemedLayoutV2 Header={Header} Sider={ThemedSiderV2}>{children}</ThemedLayoutV2>; // or just pass your custom Sider to the default layout
}
... // getData()...
This works for me. The documentation is slightly misleading I would say.
other-emerald
other-emerald3w ago
Hello @Jakub, sorry for your trouble, Nextjs works diffrent from normal react application. Actually this code is from our examples, you can see here https://github.com/refinedev/refine/blob/main/examples/with-nextjs/src/app/blog-posts/layout.tsx
GitHub
refine/examples/with-nextjs/src/app/blog-posts/layout.tsx at main ·...
A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. - refinedev/refine

Did you find this page helpful?