@tanstack/vue-table 9.0.0-beta.5 → 9.0.0-beta.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/FlexRender.cjs +2 -3
- package/dist/FlexRender.cjs.map +1 -1
- package/dist/FlexRender.js +2 -3
- package/dist/FlexRender.js.map +1 -1
- package/dist/createTableHook.cjs +4 -9
- package/dist/createTableHook.cjs.map +1 -1
- package/dist/createTableHook.d.cts +39 -12
- package/dist/createTableHook.d.ts +39 -12
- package/dist/createTableHook.js +4 -9
- package/dist/createTableHook.js.map +1 -1
- package/dist/experimental-worker-plugin.cjs +9 -0
- package/dist/experimental-worker-plugin.d.cts +1 -0
- package/dist/experimental-worker-plugin.d.ts +1 -0
- package/dist/experimental-worker-plugin.js +3 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/reactivity.cjs +2 -6
- package/dist/reactivity.cjs.map +1 -1
- package/dist/reactivity.js +2 -6
- package/dist/reactivity.js.map +1 -1
- package/dist/useTable.cjs +3 -7
- package/dist/useTable.cjs.map +1 -1
- package/dist/useTable.d.cts +1 -8
- package/dist/useTable.d.ts +1 -8
- package/dist/useTable.js +3 -7
- package/dist/useTable.js.map +1 -1
- package/package.json +8 -4
- package/skills/create-table-hook/SKILL.md +146 -0
- package/skills/getting-started/SKILL.md +144 -0
- package/skills/migrate-v8-to-v9/SKILL.md +185 -0
- package/skills/table-state/SKILL.md +191 -0
- package/skills/with-tanstack-query/SKILL.md +127 -0
- package/skills/with-tanstack-virtual/SKILL.md +116 -0
- package/src/createTableHook.ts +108 -17
- package/src/experimental-worker-plugin.ts +1 -0
- package/src/reactivity.ts +1 -2
- package/src/useTable.ts +3 -11
- package/skills/vue/client-to-server/SKILL.md +0 -365
- package/skills/vue/compose-with-tanstack-form/SKILL.md +0 -369
- package/skills/vue/compose-with-tanstack-pacer/SKILL.md +0 -318
- package/skills/vue/compose-with-tanstack-query/SKILL.md +0 -385
- package/skills/vue/compose-with-tanstack-store/SKILL.md +0 -301
- package/skills/vue/compose-with-tanstack-virtual/SKILL.md +0 -340
- package/skills/vue/getting-started/SKILL.md +0 -409
- package/skills/vue/migrate-v8-to-v9/SKILL.md +0 -375
- package/skills/vue/production-readiness/SKILL.md +0 -271
- package/skills/vue/table-state/SKILL.md +0 -403
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migrate-v8-to-v9
|
|
3
|
+
description: >
|
|
4
|
+
Complete Vue v8-to-v9 migration reference: useTable, explicit features and row-model slots, ref/atom state, FlexRender shorthand, prototype methods, type generics, sorting, sizing, selection, and logical pinning.
|
|
5
|
+
metadata:
|
|
6
|
+
type: lifecycle
|
|
7
|
+
library: '@tanstack/vue-table'
|
|
8
|
+
framework: vue
|
|
9
|
+
library_version: '9.0.0-beta.50'
|
|
10
|
+
requires:
|
|
11
|
+
- '@tanstack/table-core#migrate-v8-to-v9'
|
|
12
|
+
- getting-started
|
|
13
|
+
- table-state
|
|
14
|
+
sources:
|
|
15
|
+
- 'TanStack/table:docs/framework/vue/guide/migrating.md'
|
|
16
|
+
- 'TanStack/table:packages/vue-table/src/index.ts'
|
|
17
|
+
- 'TanStack/table:examples/vue/basic-use-table'
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
Use this as the complete breaking-change checklist. V9 is the current API; do not stop after renaming the Vue composable.
|
|
21
|
+
|
|
22
|
+
Framework prerequisite: Vue 3.2 or newer (`vue >=3.2`).
|
|
23
|
+
|
|
24
|
+
## Recommended Migration Order
|
|
25
|
+
|
|
26
|
+
1. Replace `useVueTable` with `useTable` while preserving reactive inputs.
|
|
27
|
+
2. Define explicit features, then move row models and registries into `tableFeatures`.
|
|
28
|
+
3. Update state reads, controlled ownership, and rendering.
|
|
29
|
+
4. Apply every shared API and type rename below.
|
|
30
|
+
5. Use `stockFeatures` only as a temporary audit bridge; explicit features are the production target.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
const features = tableFeatures({
|
|
34
|
+
rowSortingFeature,
|
|
35
|
+
sortedRowModel: createSortedRowModel(),
|
|
36
|
+
sortFns: { alphanumeric: sortFn_alphanumeric },
|
|
37
|
+
})
|
|
38
|
+
const data = ref(makeData())
|
|
39
|
+
const table = useTable({ features, columns, data })
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Construction and Feature Registration
|
|
43
|
+
|
|
44
|
+
| v8 | v9 |
|
|
45
|
+
| -------------------------------------------- | ---------------------------------------------------------- |
|
|
46
|
+
| `useVueTable(options)` | `useTable(options)` |
|
|
47
|
+
| All features bundled | Required `features: tableFeatures({...})` |
|
|
48
|
+
| `getCoreRowModel()` option | Remove; core row model is automatic |
|
|
49
|
+
| `get*RowModel()` table options | `create*RowModel()` slots in `tableFeatures` |
|
|
50
|
+
| `sortingFns` table option | `sortFns` feature slot |
|
|
51
|
+
| `filterFns` / `aggregationFns` table options | Same-named feature slots |
|
|
52
|
+
| Top-level `onStateChange` | Per-slice callbacks, external atoms, or store subscription |
|
|
53
|
+
|
|
54
|
+
Available feature imports are `columnFilteringFeature`, `globalFilteringFeature`, `rowSortingFeature`, `rowPaginationFeature`, `rowSelectionFeature`, `rowExpandingFeature`, `rowPinningFeature`, `columnPinningFeature`, `columnVisibilityFeature`, `columnOrderingFeature`, `columnSizingFeature`, `columnResizingFeature`, `aggregationFeature`, `columnGroupingFeature`, and `columnFacetingFeature`. APIs are feature-gated. Put every feature before its dependent slot in the same `tableFeatures` call. Aggregation is independent from grouping: register `aggregationFeature` for aggregation APIs and add `columnGroupingFeature` only for grouped rows.
|
|
55
|
+
|
|
56
|
+
### Row-model mapping
|
|
57
|
+
|
|
58
|
+
| v8 option | v9 slot and factory |
|
|
59
|
+
| -------------------------- | ------------------------------------------------------------------- |
|
|
60
|
+
| `getFilteredRowModel()` | `filteredRowModel: createFilteredRowModel()` after column filtering |
|
|
61
|
+
| `getSortedRowModel()` | `sortedRowModel: createSortedRowModel()` after row sorting |
|
|
62
|
+
| `getPaginationRowModel()` | `paginatedRowModel: createPaginatedRowModel()` after pagination |
|
|
63
|
+
| `getExpandedRowModel()` | `expandedRowModel: createExpandedRowModel()` after expanding |
|
|
64
|
+
| `getGroupedRowModel()` | `groupedRowModel: createGroupedRowModel()` after grouping |
|
|
65
|
+
| `getFacetedRowModel()` | `facetedRowModel: createFacetedRowModel()` after faceting |
|
|
66
|
+
| `getFacetedMinMaxValues()` | `facetedMinMaxValues: createFacetedMinMaxValues()` |
|
|
67
|
+
| `getFacetedUniqueValues()` | `facetedUniqueValues: createFacetedUniqueValues()` |
|
|
68
|
+
|
|
69
|
+
Factories take no arguments. Register `filterFns`, `sortFns`, and `aggregationFns` as sibling feature slots holding individually imported built-ins (`filterFn_includesString`, `sortFn_alphanumeric`, `aggregationFn_sum`) under their conventional keys. The full registry objects still work but bundle every built-in.
|
|
70
|
+
|
|
71
|
+
## Vue State Migration
|
|
72
|
+
|
|
73
|
+
- Pass a `ref` or `computed` as `data`; the adapter unwraps and syncs it. Do not pass `data.value`, which is only a snapshot. A getter returning `data.value` is also supported.
|
|
74
|
+
- `table.getState().sorting` becomes the narrow `table.atoms.sorting.get()`. Use `table.store.get()` only for a full snapshot/debug output.
|
|
75
|
+
- Wrap atom reads in Vue `computed` when deriving template values.
|
|
76
|
+
- In JSX/render functions, `table.Subscribe` provides a fine-grained boundary. Pass the callback as the explicit `children` prop because Vue JSX element children become slots.
|
|
77
|
+
- Controlled refs need getter-backed state slices plus per-slice callbacks that resolve value-or-function `Updater`s.
|
|
78
|
+
- The top-level `onStateChange` is removed. Use per-slice callbacks, external atoms, or `table.store.subscribe` to observe everything.
|
|
79
|
+
- External atoms come from `@tanstack/vue-store` and are supplied through `atoms`. Never provide both `atoms.pagination` and `state.pagination`.
|
|
80
|
+
- `table.baseAtoms` is internal writable state; prefer feature APIs or external atoms.
|
|
81
|
+
|
|
82
|
+
## Rendering and Composition
|
|
83
|
+
|
|
84
|
+
| v8 | v9 target |
|
|
85
|
+
| -------------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
86
|
+
| `<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />` | `<FlexRender :cell="cell" />` |
|
|
87
|
+
| Manual header/footer render props | `<FlexRender :header="header" />` / `:footer="footer"` |
|
|
88
|
+
| Repeated raw options | `tableOptions(...)` composition |
|
|
89
|
+
| Repeated table conventions | `createTableHook({ features, ... })` and pre-bound helpers |
|
|
90
|
+
|
|
91
|
+
The old `render`/`props` FlexRender shape still compiles, but shorthand is the migration target. `createTableHook` is optional and intended for application-wide conventions.
|
|
92
|
+
|
|
93
|
+
## Complete Shared Breaking-Change Map
|
|
94
|
+
|
|
95
|
+
### Instance methods
|
|
96
|
+
|
|
97
|
+
Row, cell, column, header, and related methods now live on shared prototypes and use `this`. Call them on their instances. Do not destructure them, pass them bare, or expect them in object spread, `Object.keys`, or JSON. Table methods are not affected.
|
|
98
|
+
|
|
99
|
+
### Logical column pinning
|
|
100
|
+
|
|
101
|
+
There are no `left`/`right` aliases in beta.38.
|
|
102
|
+
|
|
103
|
+
| old | new |
|
|
104
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
105
|
+
| `columnPinning.left` / `.right` | `.start` / `.end` |
|
|
106
|
+
| `column.pin('left' \| 'right')` | `column.pin('start' \| 'end')` |
|
|
107
|
+
| `getIsPinned() === 'left' \| 'right'` | `'start' \| 'end'` |
|
|
108
|
+
| `row.getLeftVisibleCells()` / `getRightVisibleCells()` | `getStartVisibleCells()` / `getEndVisibleCells()` |
|
|
109
|
+
| `getLeftHeaderGroups()` / `getRightHeaderGroups()` | `getStartHeaderGroups()` / `getEndHeaderGroups()` |
|
|
110
|
+
| `getLeftFooterGroups()` / `getRightFooterGroups()` | `getStartFooterGroups()` / `getEndFooterGroups()` |
|
|
111
|
+
| `getLeftFlatHeaders()` / `getRightFlatHeaders()` | `getStartFlatHeaders()` / `getEndFlatHeaders()` |
|
|
112
|
+
| `getLeftLeafHeaders()` / `getRightLeafHeaders()` | `getStartLeafHeaders()` / `getEndLeafHeaders()` |
|
|
113
|
+
| `getLeftLeafColumns()` / `getRightLeafColumns()` | `getStartLeafColumns()` / `getEndLeafColumns()` |
|
|
114
|
+
| `getLeftVisibleLeafColumns()` / `getRightVisibleLeafColumns()` | `getStartVisibleLeafColumns()` / `getEndVisibleLeafColumns()` |
|
|
115
|
+
| `getLeftTotalSize()` / `getRightTotalSize()` | `getStartTotalSize()` / `getEndTotalSize()` |
|
|
116
|
+
| `column.getStart('left')` | `column.getStart('start')` |
|
|
117
|
+
| `column.getAfter('right')` | `column.getAfter('end')` |
|
|
118
|
+
| `column.getIndex('left' \| 'right')` | `column.getIndex('start' \| 'end')` |
|
|
119
|
+
|
|
120
|
+
Use CSS `inset-inline-start`/`inset-inline-end`; logical names do not automatically set DOM direction. `columnResizeDirection` is unchanged.
|
|
121
|
+
|
|
122
|
+
### Pinning, sizing, and resizing
|
|
123
|
+
|
|
124
|
+
- `enablePinning` splits into `enableColumnPinning` and `enableRowPinning`.
|
|
125
|
+
- Interactive resizing requires `columnSizingFeature` plus `columnResizingFeature`; fixed sizing needs only the former.
|
|
126
|
+
- `columnSizingInfo` becomes `columnResizing`.
|
|
127
|
+
- `setColumnSizingInfo()` becomes `setColumnResizing()`.
|
|
128
|
+
- `onColumnSizingInfoChange` becomes `onColumnResizingChange`.
|
|
129
|
+
|
|
130
|
+
### Sorting, rows, and selection
|
|
131
|
+
|
|
132
|
+
| v8 | v9 |
|
|
133
|
+
| ------------------------------ | ----------------------------- |
|
|
134
|
+
| `sortingFn` | `sortFn` |
|
|
135
|
+
| `sortingFns` | `sortFns` |
|
|
136
|
+
| `getSortingFn()` | `getSortFn()` |
|
|
137
|
+
| `getAutoSortingFn()` | `getAutoSortFn()` |
|
|
138
|
+
| `SortingFn` / `SortingFns` | `SortFn` / `SortFns` |
|
|
139
|
+
| `row._getAllCellsByColumnId()` | `row.getAllCellsByColumnId()` |
|
|
140
|
+
|
|
141
|
+
Other `_`-prefixed internals are removed, including `_getPinnedRows`, `_getFacetedRowModel`, `_getFacetedMinMaxValues`, and `_getFacetedUniqueValues`.
|
|
142
|
+
|
|
143
|
+
`getIsSomeRowsSelected()` and `getIsSomePageRowsSelected()` now mean at least one, including all. Indeterminate UI must also check `!getIsAllRowsSelected()` or `!getIsAllPageRowsSelected()`.
|
|
144
|
+
|
|
145
|
+
## TypeScript Migration
|
|
146
|
+
|
|
147
|
+
- Add `TFeatures` first: `ColumnDef<typeof features, Person>`, `Column<typeof features, Person>`, `Row<typeof features, Person>`, `Table<typeof features, Person>`.
|
|
148
|
+
- Replace `createColumnHelper<Person>()` with `createColumnHelper<typeof features, Person>()`; use `columnHelper.columns([...])` for nested-array inference.
|
|
149
|
+
- Use `StockFeatures` when `stockFeatures` is the configuration.
|
|
150
|
+
- Existing `TableMeta`/`ColumnMeta` declaration merging must add `TFeatures` first. Prefer per-table `tableMeta`/`columnMeta: metaHelper<...>()` slots.
|
|
151
|
+
- Replace global `FilterFns`, `SortFns`, `AggregationFns`, and `FilterMeta` augmentation with registry slots and `filterMeta: metaHelper<...>()`; registered keys become valid strings in column defs.
|
|
152
|
+
- `RowData` is restricted to records or arrays; prefer explicit object row types.
|
|
153
|
+
|
|
154
|
+
## Common Migration Failures
|
|
155
|
+
|
|
156
|
+
### HIGH: Renaming only the composable
|
|
157
|
+
|
|
158
|
+
`useTable({ getSortedRowModel: ... })` is still a v8 configuration. Move the row model and its prerequisite feature into `tableFeatures`.
|
|
159
|
+
|
|
160
|
+
### HIGH: Unwrapping refs before useTable
|
|
161
|
+
|
|
162
|
+
Pass `data`, not `data.value`, or use a getter. Preserve the reactive source.
|
|
163
|
+
|
|
164
|
+
### HIGH: Passing prototype methods bare
|
|
165
|
+
|
|
166
|
+
Use `row.getValue('name')`, not `const read = row.getValue`; shallow copies also lose methods.
|
|
167
|
+
|
|
168
|
+
### MEDIUM: JSX children as slots
|
|
169
|
+
|
|
170
|
+
For `table.Subscribe`, use `children={(atoms) => ...}` explicitly.
|
|
171
|
+
|
|
172
|
+
## Final Checklist
|
|
173
|
+
|
|
174
|
+
- [ ] `useVueTable` is replaced with `useTable`; refs/computed inputs remain reactive.
|
|
175
|
+
- [ ] Features, row models, and registries are in `tableFeatures`; core row model is removed.
|
|
176
|
+
- [ ] State reads use atoms/computed or the store intentionally; `onStateChange` is removed.
|
|
177
|
+
- [ ] External atom and controlled state ownership do not overlap.
|
|
178
|
+
- [ ] FlexRender shorthand is adopted where applicable.
|
|
179
|
+
- [ ] Prototype methods, pinning, sizing/resizing, sorting, row, and selection changes are audited.
|
|
180
|
+
- [ ] Helpers, types, meta, registries, and `RowData` use v9 shapes.
|
|
181
|
+
- [ ] Temporary `stockFeatures` usage has an explicit removal plan.
|
|
182
|
+
|
|
183
|
+
## API Discovery
|
|
184
|
+
|
|
185
|
+
Inspect `node_modules/@tanstack/vue-table/src/index.ts` and `useTable.ts`; verify feature slots and exact beta APIs in `node_modules/@tanstack/table-core/src`. Do not reconstruct v9 from v8 memory.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: table-state
|
|
3
|
+
description: >
|
|
4
|
+
Read Vue-backed table.atoms/store in templates, computed, watch, or table.Subscribe; own slices with refs/computed or external Vue Store atoms; and apply updater callbacks while preserving reactive option shapes.
|
|
5
|
+
metadata:
|
|
6
|
+
type: framework
|
|
7
|
+
library: '@tanstack/vue-table'
|
|
8
|
+
framework: vue
|
|
9
|
+
library_version: '9.0.0-beta.50'
|
|
10
|
+
requires:
|
|
11
|
+
- '@tanstack/table-core#core'
|
|
12
|
+
- getting-started
|
|
13
|
+
sources:
|
|
14
|
+
- 'TanStack/table:docs/framework/vue/guide/table-state.md'
|
|
15
|
+
- 'TanStack/table:examples/vue/basic-external-state'
|
|
16
|
+
- 'TanStack/table:packages/vue-table/src/useTable.ts'
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
This skill builds on `@tanstack/table-core#core` and `getting-started`. Read them first for state ownership and Vue construction.
|
|
20
|
+
|
|
21
|
+
## State Mental Model
|
|
22
|
+
|
|
23
|
+
TanStack Table is primarily a state coordinator. Keep state internal unless another system needs to read, persist, or drive it. Without `initialState`, `atoms`, `state`, or `on[State]Change`, the table owns every registered slice.
|
|
24
|
+
|
|
25
|
+
- `table.baseAtoms` are internal writable atoms created from resolved initial state.
|
|
26
|
+
- `table.atoms` are readonly derived atoms for the active owner of each registered slice.
|
|
27
|
+
- `table.store` combines those atoms into one readonly flat store.
|
|
28
|
+
|
|
29
|
+
The Vue adapter backs atoms with refs/computed values and tracks reactive table options. Atom reads become reactive inside templates, `computed`, `watch`, or `table.Subscribe`; a read cached outside tracking is only a snapshot. State is feature-based, so a missing pagination atom or option means `rowPaginationFeature` was not registered. Keep `features` and `columns` stable; pass reactive `data` as a ref/computed instead of recreating arrays in table options.
|
|
30
|
+
|
|
31
|
+
## Setup
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { computed, ref } from 'vue'
|
|
35
|
+
import {
|
|
36
|
+
rowPaginationFeature,
|
|
37
|
+
tableFeatures,
|
|
38
|
+
useTable,
|
|
39
|
+
} from '@tanstack/vue-table'
|
|
40
|
+
|
|
41
|
+
const features = tableFeatures({ rowPaginationFeature })
|
|
42
|
+
const data = ref([{ name: 'Ada' }])
|
|
43
|
+
const columns = [{ accessorKey: 'name' }]
|
|
44
|
+
const table = useTable({ features, columns, data })
|
|
45
|
+
const pageIndex = computed(() => table.atoms.pagination.get().pageIndex)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Internal state is usually enough. Atom reads are reactive only when Vue evaluates them in a tracked template, computed, watch, or render boundary.
|
|
49
|
+
|
|
50
|
+
## Core Patterns
|
|
51
|
+
|
|
52
|
+
### Control a slice without losing updater semantics
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { computed, ref } from 'vue'
|
|
56
|
+
import type { PaginationState } from '@tanstack/vue-table'
|
|
57
|
+
|
|
58
|
+
const pagination = ref<PaginationState>({ pageIndex: 0, pageSize: 20 })
|
|
59
|
+
const controlledState = computed(() => ({ pagination: pagination.value }))
|
|
60
|
+
const onPaginationChange = (
|
|
61
|
+
next: PaginationState | ((old: PaginationState) => PaginationState),
|
|
62
|
+
) => {
|
|
63
|
+
pagination.value = typeof next === 'function' ? next(pagination.value) : next
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Pass `state: controlledState` and `onPaginationChange` to `useTable`.
|
|
68
|
+
|
|
69
|
+
### Use Subscribe as a render boundary
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
table.Subscribe({
|
|
73
|
+
children: (atoms) => <span>{atoms.pagination.get().pageIndex + 1}</span>,
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
In Vue JSX, `children` is an explicit prop, not a slot child.
|
|
78
|
+
|
|
79
|
+
## Choose State Ownership
|
|
80
|
+
|
|
81
|
+
Use exactly one owner per slice:
|
|
82
|
+
|
|
83
|
+
- Prefer internal state and feature methods for table-local behavior.
|
|
84
|
+
- Use `initialState` for starting/reset values; changing it later does not reset current state.
|
|
85
|
+
- Prefer a stable `@tanstack/vue-store` atom in `atoms` for cross-system ownership. Feature APIs update it directly, so omit `on[State]Change`.
|
|
86
|
+
- Use a ref/computed `state` value plus the matching callback for simple controlled state. Preserve the reactive wrapper and resolve raw values and updater functions.
|
|
87
|
+
|
|
88
|
+
External atoms take precedence over external `state`, which syncs into the internal base atom. Do not configure multiple owners. The global v8 `onStateChange` option is gone; observe `table.store` if all state changes matter.
|
|
89
|
+
|
|
90
|
+
## Initialize, Update, and Reset
|
|
91
|
+
|
|
92
|
+
Use feature methods such as `setSorting`, `nextPage`, `toggleVisibility`, and `toggleSelected`. Direct `baseAtoms` writes are a rare escape hatch for internally owned state; write the external atom when it owns the slice.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
table.resetSorting()
|
|
96
|
+
table.resetPagination()
|
|
97
|
+
table.resetPagination(true)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Feature resets use `table.initialState` unless `true` requests the feature default and can update external owners. Core `table.reset()` only resets internal base atoms. Use slice types such as `PaginationState`; use `TableState<typeof features>` for the complete feature-inferred state.
|
|
101
|
+
|
|
102
|
+
## Common Mistakes
|
|
103
|
+
|
|
104
|
+
### HIGH Reading an untracked snapshot
|
|
105
|
+
|
|
106
|
+
Wrong:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const pageIndex = table.atoms.pagination.get().pageIndex
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Correct:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const pageIndex = computed(() => table.atoms.pagination.get().pageIndex)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The first read is current but does not make its consumer reactive.
|
|
119
|
+
|
|
120
|
+
Source: `docs/framework/vue/guide/table-state.md`
|
|
121
|
+
|
|
122
|
+
### HIGH Passing state.value once
|
|
123
|
+
|
|
124
|
+
Wrong:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
const table = useTable({
|
|
128
|
+
features,
|
|
129
|
+
columns,
|
|
130
|
+
data,
|
|
131
|
+
state: controlledState.value,
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Correct:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const table = useTable({ features, columns, data, state: controlledState })
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The adapter watches the computed ref; a one-time `.value` breaks future option synchronization.
|
|
142
|
+
|
|
143
|
+
Source: `packages/vue-table/src/useTable.ts`
|
|
144
|
+
|
|
145
|
+
### HIGH Assigning updater functions as values
|
|
146
|
+
|
|
147
|
+
Wrong:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const onPaginationChange = (next) => {
|
|
151
|
+
pagination.value = next
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Correct:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const onPaginationChange = (next) => {
|
|
159
|
+
pagination.value = typeof next === 'function' ? next(pagination.value) : next
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Table callbacks accept either a value or a function of the previous value.
|
|
164
|
+
|
|
165
|
+
Source: `examples/vue/basic-external-state/src/App.tsx`
|
|
166
|
+
|
|
167
|
+
### MEDIUM Supplying JSX children as a slot
|
|
168
|
+
|
|
169
|
+
Wrong:
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<table.Subscribe>
|
|
173
|
+
{(atoms) => <span>{atoms.pagination.get().pageIndex}</span>}
|
|
174
|
+
</table.Subscribe>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Correct:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
<table.Subscribe
|
|
181
|
+
children={(atoms) => <span>{atoms.pagination.get().pageIndex}</span>}
|
|
182
|
+
/>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The Vue adapter declares `Subscribe(props: { children })` and expects the explicit prop.
|
|
186
|
+
|
|
187
|
+
Source: `packages/vue-table/src/useTable.ts`
|
|
188
|
+
|
|
189
|
+
## API Discovery
|
|
190
|
+
|
|
191
|
+
Inspect `node_modules/@tanstack/vue-table/src/useTable.ts` and `reactivity.ts`; inspect the exact state slice in the installed core feature directory.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: with-tanstack-query
|
|
3
|
+
description: >
|
|
4
|
+
Compose reactive Vue Query keys and results with Vue Table manual row processing, refs/computed state, server counts, and already-processed pages without duplicating query data into a drifting local ref.
|
|
5
|
+
metadata:
|
|
6
|
+
type: composition
|
|
7
|
+
library: '@tanstack/vue-table'
|
|
8
|
+
framework: vue
|
|
9
|
+
library_version: '9.0.0-beta.50'
|
|
10
|
+
requires:
|
|
11
|
+
- '@tanstack/table-core#client-vs-server'
|
|
12
|
+
- getting-started
|
|
13
|
+
- table-state
|
|
14
|
+
sources:
|
|
15
|
+
- 'TanStack/table:examples/vue/with-tanstack-query'
|
|
16
|
+
- 'TanStack/table:docs/framework/vue/guide/pagination.md'
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
This skill builds on `@tanstack/table-core#client-vs-server`, `getting-started`, and `table-state`. Name each client- and server-owned processing stage first.
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { computed, ref } from 'vue'
|
|
25
|
+
import { keepPreviousData, useQuery } from '@tanstack/vue-query'
|
|
26
|
+
import {
|
|
27
|
+
rowPaginationFeature,
|
|
28
|
+
tableFeatures,
|
|
29
|
+
useTable,
|
|
30
|
+
} from '@tanstack/vue-table'
|
|
31
|
+
|
|
32
|
+
const pagination = ref({ pageIndex: 0, pageSize: 20 })
|
|
33
|
+
const query = useQuery(() => ({
|
|
34
|
+
queryKey: ['people', pagination.value.pageIndex, pagination.value.pageSize],
|
|
35
|
+
queryFn: () =>
|
|
36
|
+
fetch(
|
|
37
|
+
`/api/people?page=${pagination.value.pageIndex}&size=${pagination.value.pageSize}`,
|
|
38
|
+
).then((r) => r.json()),
|
|
39
|
+
placeholderData: keepPreviousData,
|
|
40
|
+
}))
|
|
41
|
+
const data = computed(() => query.data.value?.rows ?? [])
|
|
42
|
+
const rowCount = computed(() => query.data.value?.rowCount ?? 0)
|
|
43
|
+
const state = computed(() => ({ pagination: pagination.value }))
|
|
44
|
+
const table = useTable({
|
|
45
|
+
features: tableFeatures({ rowPaginationFeature }),
|
|
46
|
+
columns,
|
|
47
|
+
data,
|
|
48
|
+
rowCount,
|
|
49
|
+
manualPagination: true,
|
|
50
|
+
state,
|
|
51
|
+
onPaginationChange: (next) => {
|
|
52
|
+
pagination.value =
|
|
53
|
+
typeof next === 'function' ? next(pagination.value) : next
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Core Patterns
|
|
59
|
+
|
|
60
|
+
### Keep query dependencies reactive
|
|
61
|
+
|
|
62
|
+
Use the Vue Query options function and read refs inside it. Include every manual filter/sort/page input in the query key.
|
|
63
|
+
|
|
64
|
+
### Pass Query results directly
|
|
65
|
+
|
|
66
|
+
Expose result fields as computed refs. Introduce a second local data ref only for an explicit editing workflow with a cache-write policy.
|
|
67
|
+
|
|
68
|
+
## Common Mistakes
|
|
69
|
+
|
|
70
|
+
### HIGH Unwrapping before query construction
|
|
71
|
+
|
|
72
|
+
Wrong:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const page = pagination.value.pageIndex
|
|
76
|
+
useQuery(() => ({ queryKey: ['people', page], queryFn }))
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Correct:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
useQuery(() => ({ queryKey: ['people', pagination.value.pageIndex], queryFn }))
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Only reads inside the reactive options function become query dependencies.
|
|
86
|
+
|
|
87
|
+
Source: `examples/vue/with-tanstack-query/src/App.tsx`
|
|
88
|
+
|
|
89
|
+
### HIGH Mirroring Query data locally
|
|
90
|
+
|
|
91
|
+
Wrong:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const rows = ref(query.data.value?.rows ?? [])
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Correct:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const rows = computed(() => query.data.value?.rows ?? [])
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
A one-time copy drifts from subsequent cache results.
|
|
104
|
+
|
|
105
|
+
Source: `examples/vue/with-tanstack-query/src/App.tsx`
|
|
106
|
+
|
|
107
|
+
### HIGH Omitting server counts
|
|
108
|
+
|
|
109
|
+
Wrong:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
useTable({ features, columns, data, manualPagination: true })
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Correct:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
useTable({ features, columns, data, rowCount, manualPagination: true })
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
One returned page cannot tell Table how many pages the server has.
|
|
122
|
+
|
|
123
|
+
Source: `docs/framework/vue/guide/pagination.md`
|
|
124
|
+
|
|
125
|
+
## API Discovery
|
|
126
|
+
|
|
127
|
+
Inspect installed `@tanstack/vue-table/src/useTable.ts`, installed `@tanstack/vue-query/src`, and the relevant manual Table feature source for exact option types.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: with-tanstack-virtual
|
|
3
|
+
description: >
|
|
4
|
+
Virtualize Vue Table final row or column models with reactive counts and scroll targets, stable keys, measurement, spacer geometry, sticky CSS, grid/flex widths, and infinite server data.
|
|
5
|
+
metadata:
|
|
6
|
+
type: composition
|
|
7
|
+
library: '@tanstack/vue-table'
|
|
8
|
+
framework: vue
|
|
9
|
+
library_version: '9.0.0-beta.50'
|
|
10
|
+
requires:
|
|
11
|
+
- '@tanstack/table-core#core'
|
|
12
|
+
- getting-started
|
|
13
|
+
- table-state
|
|
14
|
+
sources:
|
|
15
|
+
- 'TanStack/table:docs/framework/vue/guide/virtualization.md'
|
|
16
|
+
- 'TanStack/table:examples/vue/virtualized-rows'
|
|
17
|
+
- 'TanStack/table:examples/vue/virtualized-columns'
|
|
18
|
+
- 'TanStack/table:examples/vue/virtualized-infinite-scrolling'
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
This skill builds on `@tanstack/table-core#core`, `getting-started`, and `table-state`. Virtual consumes final Table models; it is not registered in `tableFeatures`.
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { computed, ref } from 'vue'
|
|
27
|
+
import { useVirtualizer } from '@tanstack/vue-virtual'
|
|
28
|
+
|
|
29
|
+
const scrollElement = ref<HTMLElement | null>(null)
|
|
30
|
+
const rows = computed(() => table.getRowModel().rows)
|
|
31
|
+
const rowVirtualizer = useVirtualizer(
|
|
32
|
+
computed(() => ({
|
|
33
|
+
count: rows.value.length,
|
|
34
|
+
getScrollElement: () => scrollElement.value,
|
|
35
|
+
estimateSize: () => 34,
|
|
36
|
+
getItemKey: (index) => rows.value[index]!.id,
|
|
37
|
+
overscan: 5,
|
|
38
|
+
})),
|
|
39
|
+
)
|
|
40
|
+
const virtualRows = computed(() => rowVirtualizer.value.getVirtualItems())
|
|
41
|
+
const totalSize = computed(() => rowVirtualizer.value.getTotalSize())
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Core Patterns
|
|
45
|
+
|
|
46
|
+
### Derive from current visible models
|
|
47
|
+
|
|
48
|
+
Rows come from `table.getRowModel().rows`; columns come from `table.getVisibleLeafColumns()`. Use computed options so counts and scroll targets update.
|
|
49
|
+
|
|
50
|
+
### Implement the geometry
|
|
51
|
+
|
|
52
|
+
Give the scroll container a bounded height and positioning context, create a spacer using `getTotalSize()`, and translate/measure virtual items. Follow the grid/flex examples for dynamic row heights and sticky headers.
|
|
53
|
+
|
|
54
|
+
### Coordinate infinite fetching
|
|
55
|
+
|
|
56
|
+
Fetch near the last virtual item only while `totalFetched < serverRowCount` and no request is active. Manual sorting means the server must return the sorted order and a sort change normally resets pages.
|
|
57
|
+
|
|
58
|
+
## Common Mistakes
|
|
59
|
+
|
|
60
|
+
### HIGH Passing a plain options snapshot
|
|
61
|
+
|
|
62
|
+
Wrong:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
useVirtualizer({ count: rows.value.length, getScrollElement })
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Correct:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
useVirtualizer(computed(() => ({ count: rows.value.length, getScrollElement })))
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Computed options keep the virtual range synchronized with Vue’s current model.
|
|
75
|
+
|
|
76
|
+
Source: `examples/vue/virtualized-rows/src/App.vue`
|
|
77
|
+
|
|
78
|
+
### HIGH Virtualizing source arrays
|
|
79
|
+
|
|
80
|
+
Wrong:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const rows = computed(() => data.value)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Correct:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const rows = computed(() => table.getRowModel().rows)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Source arrays do not represent Table’s current filtering, sorting, expansion, or pagination.
|
|
93
|
+
|
|
94
|
+
Source: `docs/framework/vue/guide/virtualization.md`
|
|
95
|
+
|
|
96
|
+
### HIGH Assuming Virtual provides CSS
|
|
97
|
+
|
|
98
|
+
Wrong:
|
|
99
|
+
|
|
100
|
+
```vue
|
|
101
|
+
<div v-for="item in virtualRows" :key="item.key">{{ rows[item.index].id }}</div>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Correct:
|
|
105
|
+
|
|
106
|
+
```vue
|
|
107
|
+
<div :style="{ height: `${totalSize}px`, position: 'relative' }"><div style="position:absolute"></div></div>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Virtual provides measurements, not spacer layout, transforms, sticky positioning, or Table column widths.
|
|
111
|
+
|
|
112
|
+
Source: `examples/vue/virtualized-columns/src/App.vue`
|
|
113
|
+
|
|
114
|
+
## API Discovery
|
|
115
|
+
|
|
116
|
+
Inspect installed `@tanstack/vue-table/src` and `@tanstack/vue-virtual/src`; use the maintained Vue examples for exact row, column, and infinite layout combinations.
|