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
|
# ClientVirtualTable V2 — Server Fetching Guide
This guide focuses on `fetchMode="server"` usage (Tabs 2, 2-B, 3 in `/[lng]/test/table-v2`). Client mode is unchanged from `GUIDE.md`.
## Core Concepts
- `fetchMode="server"` sets `manualPagination|manualSorting|manualFiltering|manualGrouping` to true. The table **renders what the server returns**; no client-side sorting/filtering/pagination is applied.
- You must control table state (pagination, sorting, filters, grouping, globalFilter) in the parent and refetch on change.
- Provide `rowCount` (and optionally `pageCount`) so the pagination footer is accurate.
- Export uses the current row model; in server mode it only exports the loaded page unless you fetch everything yourself.
## Minimal Wiring (Factory Service)
```tsx
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
const [sorting, setSorting] = useState([]);
const [columnFilters, setColumnFilters] = useState([]);
const [globalFilter, setGlobalFilter] = useState("");
const [data, setData] = useState([]);
const [rowCount, setRowCount] = useState(0);
const [loading, setLoading] = useState(false);
useEffect(() => {
const run = async () => {
setLoading(true);
const res = await getTableData({
pagination,
sorting,
columnFilters,
globalFilter,
});
setData(res.data);
setRowCount(res.totalRows);
setLoading(false);
};
run();
}, [pagination, sorting, columnFilters, globalFilter]);
<ClientVirtualTable
fetchMode="server"
data={data}
rowCount={rowCount}
columns={columns}
isLoading={loading}
enablePagination
pagination={pagination}
onPaginationChange={setPagination}
sorting={sorting}
onSortingChange={setSorting}
columnFilters={columnFilters}
onColumnFiltersChange={setColumnFilters}
globalFilter={globalFilter}
onGlobalFilterChange={setGlobalFilter}
/>
```
## Using `createTableService` (Pattern 2)
- Import `createTableService` in a server action and pass `columns` (accessorKey-based) plus schema/db.
- The adapter maps `sorting`, `columnFilters`, `globalFilter`, `pagination` to Drizzle query parts.
- Returned shape: `{ data, totalRows, pageCount }`. Always forward `totalRows` to the client.
## Custom Service (Pattern 3)
- Build custom joins manually; still read `tableState` for pagination/sorting/filtering if you need them.
- For sorting: map `tableState.sorting` IDs to your joined columns; provide a default order if none is set.
- Grouping in custom services requires manual implementation (see `getOrderTableDataGroupedByStatus` pattern).
## Server Grouping (Pattern 2-B)
- Only columns marked `meta.serverGroupable` in server column defs should be used.
- Group headers are fetched via DB `GROUP BY`; expanded rows are fetched per group.
- When grouping is active, the table may render a custom grouped view instead of the virtual table; ensure your fetcher returns either `{ groups }` or `{ data, totalRows }`.
## Presets in Server Mode
- Presets store: sorting, columnFilters, globalFilter, columnVisibility, columnPinning, columnOrder, grouping, pageSize.
- Loading a preset triggers the table’s `set*` APIs; parent `on*Change` handlers refetch with the restored state.
- The component resets pageIndex to 0 when applying a preset to avoid out-of-range requests after pageSize changes.
- Use unique `tableKey` per screen to avoid clashing presets across pages.
## Common Pitfalls
- Forgetting `rowCount` → pagination shows wrong totals.
- Not reacting to `sorting`/`filters`/`grouping` changes in your effect → UI toggles with no data change.
- Mapping `sorting` IDs to columns incorrectly in custom services → server ignores the sort.
- Mixing client-side models with server mode: do not enable client `getSortedRowModel`/`getFilteredRowModel` for server fetches (the component already skips them when `fetchMode="server"`).
## Feature Matrix (Server Mode)
- Sorting: Supported; must be implemented in the server fetcher.
- Filtering: Supported; column filters/global filter forwarded; implement in server.
- Pagination: Supported; manual; provide `rowCount`.
- Grouping: Client grouping is off in server mode; implement via server `GROUP BY` or custom grouped view.
- Column show/hide, pinning, reorder: Client-side only; state is preserved and sent to presets but does not affect server queries unless you opt to read it.
- Export: Exports the currently loaded rows; fetch all data yourself for full exports.
## Debug Checklist
- Confirm `fetchMode="server"` and `rowCount` are set.
- Verify the parent effect depends on `pagination`, `sorting`, `columnFilters`, `globalFilter`, and (if used) `grouping`.
- In custom services, console/log the incoming `tableState` to confirm the UI is sending the intended state.
|