Careeroza
Composition Patterns
Push Client Components to the Leaves
Keep pages and layouts on the server; make only the interactive leaf a Client Component. A search bar in a layout should not turn the whole layout into client code.
// app/layout.tsx (server)
import SearchBar from '@/components/SearchBar'; // 'use client'
import CategoryMenu from '@/components/CategoryMenu'; // server, reads DB
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<header>
<CategoryMenu />
<SearchBar />
</header>
{children}
</body>
</html>
);
}Providers Wrap Server Children
Context providers need 'use client'. Wrap them in a small client file and pass the server tree as children, so the pages stay Server Components:
// app/providers.tsx
'use client';
import { ThemeProvider } from '@/components/theme';
import { CartProvider } from '@/components/cart';
export default function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider>
<CartProvider>{children}</CartProvider>
</ThemeProvider>
);
}
// app/layout.tsx (server)
// <body><Providers>{children}</Providers></body>Third-party Client Libraries
A library component that uses hooks but has no 'use client' (for example an older carousel) fails in a Server Component. Re-export it from a client file:
// components/Carousel.tsx
'use client';
export { default } from 'react-slick';Rule of Thumb
| Pattern | OK? |
|---|---|
| Server imports Client | Yes |
Client receives Server as children / props | Yes |
| Client imports Server | No — it becomes client code (and fails if it is async or server-only) |