I’m currently working on a project using Next.js 14 and Drizzle ORM. I have a server component (page.tsx) where I fetch data using Drizzle ORM and pass it down to a client component (tabs.tsx), which then passes it further down to another child component (services.tsx).
My questions are:
-
Is the following the right way to structure and pass down the data?
-
Are there better alternatives or practices, especially considering that Drizzle generates auto types?
Any advice or insights on improving this approach would be greatly appreciated!
Here is my current code structure:
page.tsx (server component):
...
import { db } from "@/db";
export default async function Page() {
const categories = await db.query.categories.findMany({
with: {
subCategories: {
with: {
services: true,
},
},
},
});
return (
<div className="grid h-full grid-cols-3 gap-6">
<Tabs categories={categories}></Tabs>
...
</div>
);
}
tabs.tsx (client component):
"use client";
...
import { Category } from "@/types";
import Services from "./services";
export interface TabsProps {
categories: Category[];
}
export default function Tabs({ categories }: TabsProps) {
...
return (
<Root
className="flex flex-col overflow-y-auto rounded-lg border border-border"
defaultValue="tab1"
>
...
<ScrollArea className="h-full grow">
...
<div className="flex flex-col gap-6 p-6">
<Services categories={categories}></Services>
...
</div>
</Content>
</ScrollArea>
</Root>
);
}
services.tsx (nested child component):
...
import { Category } from "@/types";
export interface ServicesProps {
categories: Category[];
}
export default function Services({ categories }: ServicesProps) {
return (
<div className="flex flex-col gap-6 rounded-lg border border-border p-6">
...
<div className="flex gap-6">
{categories.map((category, index) => (
<button
className="rounded-lg border border-border p-3 hover:bg-muted"
key={index}
>
{category.name}
</button>
))}
</div>
</div>
);
}
To pass categories down to Services, I defined the type for the interface in a separate file:
types.ts
import { InferSelectModel } from "drizzle-orm";
import { categories, subCategories, services } from "@/schema";
export type Category = InferSelectModel<typeof categories> & {
subCategories: (InferSelectModel<typeof subCategories> & {
services: InferSelectModel<typeof services>[];
})[];
};