# Table Component & Data Fetching Guide 이 가이드는 `ClientVirtualTable`을 사용하여 테이블을 구현하고, 데이터를 페칭하는 3가지 주요 패턴을 설명합니다. ## 개요 프로젝트의 복잡도와 요구사항에 따라 아래 3가지 패턴 중 하나를 선택하여 사용할 수 있습니다. | 모드 | 패턴 | 적합한 상황 | 특징 | |---|---|---|---| | **Client** | 1. Client-Side | 데이터가 적을 때 (< 1000건), 빠른 인터랙션 필요 | 전체 데이터 로드 후 브라우저에서 처리 | | **Server** | 2. Factory Service | 단순 CRUD, 마스터 테이블 | 코드 1줄로 서버 액션 생성, 빠른 개발 | | **Server** | 3. Custom Service | 복잡한 조인, 비즈니스 로직 | 완전한 쿼리 제어, Adapter를 도구로 사용 | --- ## 1. Client-Side (기본 모드) 데이터가 많지 않을 때 가장 간단한 방법입니다. 모든 데이터를 한 번에 받아와 `data` prop으로 넘깁니다. ### 사용법 ```tsx // page.tsx import { getAllUsers } from "@/lib/api/users"; import { ClientVirtualTable } from "@/components/client-table-v2/client-virtual-table"; import { columns } from "./columns"; export default async function UsersPage() { const users = await getAllUsers(); // 전체 목록 조회 return ( ); } ``` --- ## 2. Factory Service (추천 - 단순 조회용) `createTableService`를 사용하여 서버 사이드 페칭을 위한 액션을 자동으로 생성합니다. ### 1) Server Action 생성 ```typescript // app/actions/user-table.ts "use server" import { db } from "@/lib/db"; import { users } from "@/lib/db/schema"; import { columns } from "@/components/users/columns"; import { createTableService } from "@/components/client-table-v2/adapter/create-table-service"; // 팩토리 함수로 액션 생성 (한 줄로 끝!) export const getUserTableData = createTableService({ db, schema: users, columns: columns }); ``` ### 2) 클라이언트 컴포넌트 연결 ```tsx // components/users/user-table.tsx "use client" import { getUserTableData } from "@/app/actions/user-table"; import { ClientVirtualTable } from "@/components/client-table-v2/client-virtual-table"; import { columns } from "./columns"; import { useState, useEffect } from "react"; export function UserTable() { const [data, setData] = useState([]); const [totalRows, setTotalRows] = useState(0); const [loading, setLoading] = useState(false); // 테이블 상태 관리 const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); const [sorting, setSorting] = useState([]); const [columnFilters, setColumnFilters] = useState([]); const [globalFilter, setGlobalFilter] = useState(""); // 데이터 페칭 useEffect(() => { const fetchData = async () => { setLoading(true); const result = await getUserTableData({ pagination, sorting, columnFilters, globalFilter }); setData(result.data); setTotalRows(result.totalRows); setLoading(false); }; fetchData(); }, [pagination, sorting, columnFilters, globalFilter]); return ( ); } ``` --- ## 3. Custom Service (복잡한 로직용) 여러 테이블을 조인하거나, 특정 권한 체크 등 복잡한 로직이 필요할 때는 `DrizzleTableAdapter`를 직접 사용합니다. ### 1) Custom Server Action 작성 ```typescript // app/actions/order-table.ts "use server" import { db } from "@/lib/db"; import { orders, users } from "@/lib/db/schema"; import { DrizzleTableAdapter } from "@/components/client-table-v2/adapter/drizzle-table-adapter"; import { count, eq } from "drizzle-orm"; export async function getOrderTableData(tableState) { // 1. 어댑터로 조건절 생성 const adapter = new DrizzleTableAdapter(orders, columns); const { where, orderBy, limit, offset } = adapter.getQueryParts(tableState); // 2. 커스텀 쿼리 작성 (예: 유저 조인) const data = await db .select({ orderId: orders.id, amount: orders.amount, userName: users.name // 조인된 컬럼 }) .from(orders) .leftJoin(users, eq(orders.userId, users.id)) .where(where) .orderBy(...orderBy) .limit(limit) .offset(offset); // 3. 카운트 쿼리 const total = await db .select({ count: count() }) .from(orders) .where(where); return { data, totalRows: total[0]?.count ?? 0 }; } ``` ### 2) 클라이언트 연결 Factory Service 방식과 동일하게 `useEffect`에서 `getOrderTableData`를 호출하면 됩니다.