@tanstack/react-table 9.0.0-alpha.9 → 9.0.0-beta.1
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 +127 -0
- package/dist/FlexRender.cjs +61 -0
- package/dist/FlexRender.cjs.map +1 -0
- package/dist/FlexRender.d.cts +51 -0
- package/dist/FlexRender.d.ts +51 -0
- package/dist/FlexRender.js +58 -0
- package/dist/FlexRender.js.map +1 -0
- package/dist/Subscribe.cjs +13 -0
- package/dist/Subscribe.cjs.map +1 -0
- package/dist/Subscribe.d.cts +101 -0
- package/dist/Subscribe.d.ts +101 -0
- package/dist/Subscribe.js +13 -0
- package/dist/Subscribe.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/createTableHook.cjs +313 -0
- package/dist/createTableHook.cjs.map +1 -0
- package/dist/createTableHook.d.cts +358 -0
- package/dist/createTableHook.d.ts +358 -0
- package/dist/createTableHook.js +311 -0
- package/dist/createTableHook.js.map +1 -0
- package/dist/flex-render.cjs +5 -0
- package/dist/flex-render.d.cts +2 -0
- package/dist/flex-render.d.ts +2 -0
- package/dist/flex-render.js +3 -0
- package/dist/index.cjs +18 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +8 -0
- package/dist/legacy.cjs +14 -0
- package/dist/legacy.d.cts +2 -0
- package/dist/legacy.d.ts +2 -0
- package/dist/legacy.js +3 -0
- package/dist/reactivity.cjs +34 -0
- package/dist/reactivity.cjs.map +1 -0
- package/dist/reactivity.js +34 -0
- package/dist/reactivity.js.map +1 -0
- package/dist/static-functions.cjs +9 -0
- package/dist/static-functions.d.cts +1 -0
- package/dist/static-functions.d.ts +1 -0
- package/dist/static-functions.js +3 -0
- package/dist/useLegacyTable.cjs +191 -0
- package/dist/useLegacyTable.cjs.map +1 -0
- package/dist/useLegacyTable.d.cts +233 -0
- package/dist/useLegacyTable.d.ts +233 -0
- package/dist/useLegacyTable.js +181 -0
- package/dist/useLegacyTable.js.map +1 -0
- package/dist/useTable.cjs +72 -0
- package/dist/useTable.cjs.map +1 -0
- package/dist/useTable.d.cts +122 -0
- package/dist/useTable.d.ts +122 -0
- package/dist/useTable.js +72 -0
- package/dist/useTable.js.map +1 -0
- package/package.json +41 -22
- package/skills/react/client-to-server/SKILL.md +377 -0
- package/skills/react/compose-with-tanstack-form/SKILL.md +363 -0
- package/skills/react/compose-with-tanstack-pacer/SKILL.md +287 -0
- package/skills/react/compose-with-tanstack-query/SKILL.md +467 -0
- package/skills/react/compose-with-tanstack-store/SKILL.md +347 -0
- package/skills/react/compose-with-tanstack-virtual/SKILL.md +388 -0
- package/skills/react/compose-with-tanstack-virtual/references/column-virtualization-and-infinite-scroll.md +136 -0
- package/skills/react/getting-started/SKILL.md +388 -0
- package/skills/react/migrate-v8-to-v9/SKILL.md +488 -0
- package/skills/react/production-readiness/SKILL.md +341 -0
- package/skills/react/react-subscribe-compiler-compat/SKILL.md +269 -0
- package/skills/react/table-state/SKILL.md +432 -0
- package/src/FlexRender.tsx +136 -0
- package/src/Subscribe.ts +153 -0
- package/src/createTableHook.tsx +1121 -0
- package/src/flex-render.ts +1 -0
- package/src/index.ts +6 -0
- package/src/legacy.ts +3 -0
- package/src/reactivity.ts +41 -0
- package/src/static-functions.ts +1 -0
- package/src/useLegacyTable.ts +487 -0
- package/src/useTable.ts +191 -0
- package/dist/cjs/index.cjs +0 -77
- package/dist/cjs/index.cjs.map +0 -1
- package/dist/cjs/index.d.cts +0 -9
- package/dist/esm/index.d.ts +0 -9
- package/dist/esm/index.js +0 -55
- package/dist/esm/index.js.map +0 -1
- package/src/index.tsx +0 -92
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react/compose-with-tanstack-store
|
|
3
|
+
description: >
|
|
4
|
+
`@tanstack/react-table` v9 is built on TanStack Store. Each state slice
|
|
5
|
+
(sorting, pagination, rowSelection, columnFilters, …) is a separate atom.
|
|
6
|
+
The table exposes three READ surfaces — `table.atoms.<slice>` (per-slice
|
|
7
|
+
readonly), `table.store` (flat readonly view), `table.state` (selector
|
|
8
|
+
output from `useTable`) — and two WRITE paths — internal
|
|
9
|
+
`table.baseAtoms.<slice>` OR YOUR `options.atoms[slice]` if you opt to own
|
|
10
|
+
the slice. Use `useCreateAtom` from `@tanstack/react-store` for stable
|
|
11
|
+
identity, `useSelector` for fine-grained reads, and pass the atom in
|
|
12
|
+
`options.atoms` so the table writes through it directly — no `on*Change`
|
|
13
|
+
handler required.
|
|
14
|
+
type: composition
|
|
15
|
+
library: tanstack-table
|
|
16
|
+
framework: react
|
|
17
|
+
library_version: '9.0.0-alpha.48'
|
|
18
|
+
requires:
|
|
19
|
+
- react/table-state
|
|
20
|
+
- state-management
|
|
21
|
+
sources:
|
|
22
|
+
- TanStack/table:docs/framework/react/guide/table-state.md
|
|
23
|
+
- TanStack/table:examples/react/basic-external-atoms/src/main.tsx
|
|
24
|
+
- TanStack/table:examples/react/basic-subscribe/src/main.tsx
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
This skill builds on `tanstack-table/state-management` and `tanstack-table/react/table-state`. Read those first — `state-management` explains the atom model conceptually; `table-state` covers the basic React adapter. This skill goes deeper into composition with `@tanstack/react-store`.
|
|
28
|
+
|
|
29
|
+
## What "compose with TanStack Store" means in practice
|
|
30
|
+
|
|
31
|
+
A v9 React table is already a Store consumer — every slice (`sorting`, `pagination`, `rowSelection`, `columnFilters`, `columnVisibility`, …) is an atom managed by Store. Composing with Store means **opting to own one or more of those atoms yourself** so you can:
|
|
32
|
+
|
|
33
|
+
- Share a slice across multiple components without prop-drilling the table instance.
|
|
34
|
+
- Share a slice across multiple **tables** (e.g. a global filter atom).
|
|
35
|
+
- Persist a slice (subscribe to localStorage outside the table).
|
|
36
|
+
- Integrate with other atom-based code (atoms in your data layer).
|
|
37
|
+
- Skip the `on*Change` callback dance — the table writes through your atom directly.
|
|
38
|
+
|
|
39
|
+
## Setup
|
|
40
|
+
|
|
41
|
+
Install `@tanstack/react-store` if you don't already have it (it's a peer of `@tanstack/react-table`):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pnpm add @tanstack/react-store
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Three APIs do the work:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { useCreateAtom, useSelector } from '@tanstack/react-store'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- `useCreateAtom<T>(initial)` — create an atom with stable identity inside a component (React-safe replacement for `useRef(createAtom(...))`).
|
|
54
|
+
- `useSelector(atomOrStore, selector?)` — subscribe a component to an atom or store.
|
|
55
|
+
- The table's `options.atoms` option — hand ownership of named slices to your atoms.
|
|
56
|
+
|
|
57
|
+
## Core Patterns
|
|
58
|
+
|
|
59
|
+
### 1. Own a slice externally
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import { useCreateAtom, useSelector } from '@tanstack/react-store'
|
|
63
|
+
import {
|
|
64
|
+
useTable,
|
|
65
|
+
tableFeatures,
|
|
66
|
+
rowSortingFeature,
|
|
67
|
+
rowPaginationFeature,
|
|
68
|
+
createSortedRowModel,
|
|
69
|
+
createPaginatedRowModel,
|
|
70
|
+
sortFns,
|
|
71
|
+
} from '@tanstack/react-table'
|
|
72
|
+
import type { PaginationState, SortingState } from '@tanstack/react-table'
|
|
73
|
+
|
|
74
|
+
const features = tableFeatures({ rowSortingFeature, rowPaginationFeature })
|
|
75
|
+
|
|
76
|
+
function MyTable({ columns, data }) {
|
|
77
|
+
const sortingAtom = useCreateAtom<SortingState>([])
|
|
78
|
+
const paginationAtom = useCreateAtom<PaginationState>({
|
|
79
|
+
pageIndex: 0,
|
|
80
|
+
pageSize: 10,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// Fine-grained reads — each component re-renders independently.
|
|
84
|
+
const sorting = useSelector(sortingAtom)
|
|
85
|
+
const pagination = useSelector(paginationAtom)
|
|
86
|
+
|
|
87
|
+
const table = useTable({
|
|
88
|
+
features,
|
|
89
|
+
rowModels: {
|
|
90
|
+
sortedRowModel: createSortedRowModel(sortFns),
|
|
91
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
92
|
+
},
|
|
93
|
+
columns,
|
|
94
|
+
data,
|
|
95
|
+
atoms: { sorting: sortingAtom, pagination: paginationAtom },
|
|
96
|
+
// NOTE: no onSortingChange / onPaginationChange — table writes to atoms directly.
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
// You own the atom → you own its reset.
|
|
100
|
+
const resetMyState = () => {
|
|
101
|
+
sortingAtom.set([])
|
|
102
|
+
paginationAtom.set({ pageIndex: 0, pageSize: 10 })
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Source: `examples/react/basic-external-atoms/src/main.tsx`.
|
|
108
|
+
|
|
109
|
+
### 2. Read a table-owned atom from a sibling component
|
|
110
|
+
|
|
111
|
+
You don't have to own a slice to read it surgically — `table.atoms.<slice>` works with `useSelector` too.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
function SelectedCount({ table }) {
|
|
115
|
+
// Re-renders ONLY when rowSelection changes.
|
|
116
|
+
const selection = useSelector(table.atoms.rowSelection)
|
|
117
|
+
return <span>{Object.keys(selection).length} selected</span>
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. Persist a slice to localStorage
|
|
122
|
+
|
|
123
|
+
Because you own the atom, you can do anything you want outside the table render path:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
const visibilityAtom = useCreateAtom<Record<string, boolean>>(() =>
|
|
127
|
+
JSON.parse(localStorage.getItem('cv') ?? '{}'),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
React.useEffect(() => {
|
|
131
|
+
return visibilityAtom.subscribe(() => {
|
|
132
|
+
localStorage.setItem('cv', JSON.stringify(visibilityAtom.get()))
|
|
133
|
+
})
|
|
134
|
+
}, [visibilityAtom])
|
|
135
|
+
|
|
136
|
+
const table = useTable({
|
|
137
|
+
features,
|
|
138
|
+
rowModels: {},
|
|
139
|
+
columns,
|
|
140
|
+
data,
|
|
141
|
+
atoms: { columnVisibility: visibilityAtom },
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 4. Share one slice across multiple tables
|
|
146
|
+
|
|
147
|
+
Create the atom outside any component (or in a parent and pass down):
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { createAtom } from '@tanstack/store'
|
|
151
|
+
|
|
152
|
+
const globalFilterAtom = createAtom('')
|
|
153
|
+
|
|
154
|
+
function UsersTable() {
|
|
155
|
+
return <Table data={users} filter={globalFilterAtom} />
|
|
156
|
+
}
|
|
157
|
+
function OrdersTable() {
|
|
158
|
+
return <Table data={orders} filter={globalFilterAtom} />
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function Table({ data, filter }) {
|
|
162
|
+
const table = useTable({
|
|
163
|
+
features,
|
|
164
|
+
rowModels: {
|
|
165
|
+
/* … */
|
|
166
|
+
},
|
|
167
|
+
columns,
|
|
168
|
+
data,
|
|
169
|
+
atoms: { globalFilter: filter },
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Read surfaces and write paths — cheat sheet
|
|
175
|
+
|
|
176
|
+
| Surface | Reactive | Use case |
|
|
177
|
+
| ----------------------------------- | --------------------------- | --------------------------------------------------------------- |
|
|
178
|
+
| `table.state` | ✓ (via `useTable` selector) | Default top-level reads in the component that called `useTable` |
|
|
179
|
+
| `<table.Subscribe>` / `<Subscribe>` | ✓ | Surgical re-render boundaries inside the tree |
|
|
180
|
+
| `useSelector(table.atoms.X)` | ✓ | Narrowest possible subscription to one slice |
|
|
181
|
+
| `table.atoms.X.get()` | ✗ current-value read | Inside event handlers / effects |
|
|
182
|
+
| `table.state` | ✗ current-value read | Debugging / one-shot reads |
|
|
183
|
+
|
|
184
|
+
| Write path | Owner | Effect |
|
|
185
|
+
| ------------------------------- | ----------------- | ---------------------------------------------------------------------------------- |
|
|
186
|
+
| Internal `table.baseAtoms.X` | The table | Used when you provide neither `options.atoms.X` nor `options.state.X` |
|
|
187
|
+
| `options.atoms.X` (yours) | You | Table writes through; you can `.set()` from anywhere |
|
|
188
|
+
| `options.state.X` + `onXChange` | You (React state) | Classic controlled state. Cannot coexist with `options.atoms.X` for the same slice |
|
|
189
|
+
|
|
190
|
+
Precedence: `options.atoms[key]` > `options.state[key]` > internal.
|
|
191
|
+
|
|
192
|
+
## Common Mistakes
|
|
193
|
+
|
|
194
|
+
### CRITICAL Creating the atom with `createAtom(...)` inside the component body
|
|
195
|
+
|
|
196
|
+
Wrong:
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
function MyTable() {
|
|
200
|
+
const sortingAtom = createAtom<SortingState>([]) // new atom every render
|
|
201
|
+
useTable({
|
|
202
|
+
features,
|
|
203
|
+
rowModels: {},
|
|
204
|
+
columns,
|
|
205
|
+
data,
|
|
206
|
+
atoms: { sorting: sortingAtom },
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Correct:
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
function MyTable() {
|
|
215
|
+
const sortingAtom = useCreateAtom<SortingState>([]) // stable across renders
|
|
216
|
+
useTable({
|
|
217
|
+
features,
|
|
218
|
+
rowModels: {},
|
|
219
|
+
columns,
|
|
220
|
+
data,
|
|
221
|
+
atoms: { sorting: sortingAtom },
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
A fresh atom every render rebinds the table to a new atom whose state is the initial value — the slice resets on every render.
|
|
227
|
+
Source: `examples/react/basic-external-atoms/src/main.tsx`.
|
|
228
|
+
|
|
229
|
+
### HIGH Passing the same slice via `state` AND `atoms`
|
|
230
|
+
|
|
231
|
+
Wrong:
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
useTable({
|
|
235
|
+
features,
|
|
236
|
+
rowModels: {},
|
|
237
|
+
columns,
|
|
238
|
+
data,
|
|
239
|
+
state: { sorting: localSorting }, // silently ignored
|
|
240
|
+
onSortingChange: setLocalSorting, // silently ignored
|
|
241
|
+
atoms: { sorting: sortingAtom }, // wins
|
|
242
|
+
})
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Correct:
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
// Pick exactly one ownership mechanism per slice.
|
|
249
|
+
useTable({
|
|
250
|
+
features,
|
|
251
|
+
rowModels: {},
|
|
252
|
+
columns,
|
|
253
|
+
data,
|
|
254
|
+
atoms: { sorting: sortingAtom },
|
|
255
|
+
})
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`options.atoms[key]` > `options.state[key]`. Confusing to debug because the `state` plumbing looks live but does nothing.
|
|
259
|
+
Source: `docs/framework/react/guide/table-state.md`.
|
|
260
|
+
|
|
261
|
+
### HIGH Pairing external atoms with `on*Change` handlers
|
|
262
|
+
|
|
263
|
+
Wrong:
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
useTable({
|
|
267
|
+
features,
|
|
268
|
+
rowModels: {},
|
|
269
|
+
columns,
|
|
270
|
+
data,
|
|
271
|
+
atoms: { sorting: sortingAtom },
|
|
272
|
+
onSortingChange: (next) => sortingAtom.set(next), // redundant + confusing
|
|
273
|
+
})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Correct:
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
useTable({
|
|
280
|
+
features,
|
|
281
|
+
rowModels: {},
|
|
282
|
+
columns,
|
|
283
|
+
data,
|
|
284
|
+
atoms: { sorting: sortingAtom },
|
|
285
|
+
})
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The table writes directly to the atom you provided via the atom's `set()`. Adding an `on*Change` does nothing useful and confuses readers.
|
|
289
|
+
Source: `examples/react/basic-external-atoms/src/main.tsx`.
|
|
290
|
+
|
|
291
|
+
### HIGH Expecting `table.reset()` to clear externally-owned atoms
|
|
292
|
+
|
|
293
|
+
Wrong:
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
<button onClick={() => table.reset()}>Reset</button>
|
|
297
|
+
// External atoms remain at their current values — table can't reset what it doesn't own.
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Correct:
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
<button
|
|
304
|
+
onClick={() => {
|
|
305
|
+
sortingAtom.set([])
|
|
306
|
+
paginationAtom.set({ pageIndex: 0, pageSize: 10 })
|
|
307
|
+
table.reset() // resets the slices the table still owns
|
|
308
|
+
}}
|
|
309
|
+
>
|
|
310
|
+
Reset
|
|
311
|
+
</button>
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
The table only resets slices it manages internally. Your atoms are yours to reset.
|
|
315
|
+
Source: `docs/framework/react/guide/table-state.md`.
|
|
316
|
+
|
|
317
|
+
### MEDIUM Reading via `table.state.sorting` in deeply-nested components
|
|
318
|
+
|
|
319
|
+
Wrong:
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
function SortIndicator({ table }) {
|
|
323
|
+
const { sorting } = table.state // re-renders when ANY state slice changes
|
|
324
|
+
return <span>{sorting.length} cols</span>
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Correct:
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
import { useSelector } from '@tanstack/react-store'
|
|
332
|
+
|
|
333
|
+
function SortIndicator({ table }) {
|
|
334
|
+
const sorting = useSelector(table.atoms.sorting) // re-renders only on sorting changes
|
|
335
|
+
return <span>{sorting.length} cols</span>
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`useSelector(table.atoms.X)` is the narrowest subscription surface — skips constructing a state snapshot.
|
|
340
|
+
Source: `docs/framework/react/guide/table-state.md`.
|
|
341
|
+
|
|
342
|
+
## See Also
|
|
343
|
+
|
|
344
|
+
- `tanstack-table/react/table-state` — the base API, includes `<Subscribe>` and `<table.Subscribe>` shapes.
|
|
345
|
+
- `tanstack-table/react/compose-with-tanstack-query` — Query queryKey keyed on a Store atom is the canonical pattern.
|
|
346
|
+
- `tanstack-table/react/production-readiness` — narrowing selectors and per-slice subscriptions.
|
|
347
|
+
- `tanstack-table/react/client-to-server` — atoms make manual-mode wiring trivial.
|