summaryrefslogtreecommitdiff
path: root/components/client-table-v2/GUIDE.md
blob: 4ccadfc7da0acb46dea907a0895ca41f4e56b663 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# 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 (
    <ClientVirtualTable 
      fetchMode="client"
      data={users}
      columns={columns}
      enablePagination
      enableSorting
      enableFiltering
    />
  );
}
```

---

## 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 (
    <ClientVirtualTable 
      fetchMode="server"
      data={data}
      rowCount={totalRows}
      columns={columns}
      isLoading={loading}
      // 상태 연결
      pagination={pagination} onPaginationChange={setPagination}
      sorting={sorting} onSortingChange={setSorting}
      columnFilters={columnFilters} onColumnFiltersChange={setColumnFilters}
      globalFilter={globalFilter} onGlobalFilterChange={setGlobalFilter}
    />
  );
}
```

---

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