# 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`를 호출하면 됩니다.