Skip to content

Commit 8412d5d

Browse files
riccardoperraautofix-ci[bot]KevinVandy
authored
feat: enable support for native reactivity in solid vue adapters (#6298)
* chore: update examples to use table.store.get() instead of removed table.state * feat: refactor solid/vue native reactivity adapter * ci: apply automated fixes * ci: apply automated fixes (attempt 2/3) * fix: update all examples to call table.atoms instead of table.store * ci: apply automated fixes * fix(vue): call reactivity unmount on scope dispose * correct merge conflict resolution and regen lock file * fix sherif issue * update table state docs --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Kevin Van Cott <kevinvandy656@gmail.com>
1 parent 0d982ee commit 8412d5d

90 files changed

Lines changed: 770 additions & 1281 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/framework/angular/guide/table-state.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ A table instance has a few state surfaces:
2828

2929
- `table.baseAtoms` are the internal writable atoms created from the resolved initial state.
3030
- `table.atoms` are readonly derived atoms exposed per registered state slice.
31-
- `table.state` is a readonly flat proxy over the registered `table.atoms`, useful for full-state debug output.
32-
- `table.store` is the underlying readonly flat TanStack Store. Prefer `table.atoms` or `table.state` in app code.
31+
- `table.store` is the readonly flat TanStack Store derived by putting all of the registered `table.atoms` together.
3332

3433
The Angular adapter provides `angularReactivity(injector)` as the table's reactivity binding. Core readonly atoms are Angular `computed` values, writable atoms are Angular `signal` values, and subscriptions bridge through `toObservable(computed(...), { injector })`. `injectTable` reruns the options initializer when Angular signals read inside it change, then calls `table.setOptions`.
3534

@@ -61,7 +60,7 @@ this.table.atoms.sorting.get()
6160
// this.table.atoms.rowSelection // TypeScript error unless rowSelectionFeature is registered
6261
```
6362

64-
If `features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `initialState`, `state`, or `atoms`.
63+
If `features` does not include a feature, its state should not be available in `table.atoms`, `table.store.get()`, `initialState`, `state`, or `atoms`.
6564

6665
### Accessing Table State
6766

@@ -81,11 +80,11 @@ const pagination = this.table.atoms.pagination.get()
8180
const sorting = this.table.atoms.sorting.get()
8281
```
8382

84-
Use `table.state` when you need the current flat state shape, such as debug JSON:
83+
Use `table.store.get()` when you need the current flat state shape, such as debug JSON:
8584

8685
```ts
87-
const tableState = this.table.state
88-
const stateJson = JSON.stringify(this.table.state, null, 2)
86+
const tableState = this.table.store.get()
87+
const stateJson = JSON.stringify(this.table.store.get(), null, 2)
8988
```
9089

9190
Atom reads are signal reads in Angular. If `this.table.atoms.pagination.get()` is used in a template expression, `computed(...)`, or `effect(...)`, Angular tracks it and updates when that atom changes.
@@ -116,11 +115,11 @@ readonly pagination = computed(
116115
readonly pageIndex = computed(() => this.pagination().pageIndex)
117116
```
118117

119-
You can also select from the flat state proxy if that is more convenient, but prefer direct atoms for narrow render reads.
118+
You can also select from the flat store snapshot if that is more convenient, but prefer direct atoms for narrow render reads.
120119

121120
```ts
122121
readonly pagination = computed(
123-
() => this.table.state.pagination,
122+
() => this.table.store.get().pagination,
124123
{ equal: shallow },
125124
)
126125
```
@@ -243,7 +242,7 @@ readonly table = injectTable(() => ({
243242
}))
244243
```
245244

246-
The v8-style `onStateChange` option is no longer part of the v9 `injectTable` state model. v9 encourages keeping table state slices atomic and separated for performance.
245+
Use the per-slice `on[State]Change` callbacks to keep controlled table state slices atomic and separated.
247246

248247
##### On State Change Callbacks
249248

docs/framework/solid/guide/table-state.md

Lines changed: 69 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ A table instance has a few state surfaces:
3232
- `table.baseAtoms` are the internal writable atoms created from the resolved initial state.
3333
- `table.atoms` are readonly derived atoms exposed per registered state slice.
3434
- `table.store` is a readonly flat TanStack Store derived by putting all of the registered `table.atoms` together.
35-
- `table.state()` is Solid-only selected state. It is the accessor returned from the selector passed as the second argument to `createTable`.
3635

3736
The Solid adapter provides `solidReactivity(owner)` to the table's `coreReativityFeature`. Core readonly atoms are Solid `createMemo` values and core writable atoms are Solid `createSignal` values. Because atom `.get()` reads through Solid signals and memos, table APIs can be consumed inside Solid computations and update only the computations that read the relevant state.
3837

@@ -64,7 +63,7 @@ table.atoms.sorting.get()
6463
// table.atoms.rowSelection // TypeScript error unless rowSelectionFeature is registered
6564
```
6665

67-
If `features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `table.state()`, `initialState`, `state`, or `atoms`.
66+
If `features` does not include a feature, its state should not be available in `table.atoms`, `table.store.get()`, `initialState`, `state`, or `atoms`.
6867

6968
### Accessing Table State
7069

@@ -73,9 +72,9 @@ There are two different questions when reading table state:
7372
- Do you only need the current value?
7473
- Or should a Solid computation update when that value changes?
7574

76-
Use a direct atom or store read for the current value. Use a selector, accessor, or `table.Subscribe` when you want Solid's fine-grained updates.
75+
Use direct atom reads for slice values. Use `table.store.get()` for the current flat state snapshot. Because Solid table atoms are backed by Solid signals and memos, atom reads participate in Solid dependency tracking when they happen inside JSX, `createMemo(...)`, `createEffect(...)`, or `table.Subscribe`.
7776

78-
#### Reading State Without Subscribing
77+
#### Reading State
7978

8079
The simplest and most performant way to read a current state value is to read the matching atom:
8180

@@ -87,77 +86,92 @@ const sorting = table.atoms.sorting.get()
8786
You can also read the current flat store snapshot:
8887

8988
```tsx
90-
const tableState = table.store.state
91-
const pagination = table.store.state.pagination
89+
const tableState = table.store.get()
90+
const pagination = table.store.get().pagination
9291
```
9392

94-
These reads are current-value reads. They only participate in Solid dependency tracking when they are called inside a Solid reactive scope that tracks those reads. If the UI needs to stay reactive to table state changes, use `table.state()`, `table.Subscribe`, or even a `useSelector` hook from TanStack Store.
93+
These reads are current-value reads. They only participate in Solid dependency tracking when they are called inside a Solid reactive scope that tracks those reads. Prefer `table.atoms.<slice>.get()` for narrow reactive reads. Use `table.store.get()` for full-state debug output or when a computation intentionally depends on the whole table state.
9594

96-
#### Reading Reactive State with createTable
95+
#### Reading Reactive State with Solid
9796

98-
The second argument to `createTable` is a TanStack Store selector. The selected value is exposed as `table.state()`. The default selector selects all registered table state.
97+
Use Solid's native primitives to derive reactive values from table atoms or the flat store snapshot.
9998

10099
```tsx
101-
const table = createTable(
102-
{
103-
features,
104-
rowModels: {
105-
paginatedRowModel: createPaginatedRowModel(),
106-
},
107-
columns,
108-
get data() {
109-
return data()
110-
},
100+
const table = createTable({
101+
features,
102+
rowModels: {
103+
paginatedRowModel: createPaginatedRowModel(),
111104
},
112-
(state) => ({
113-
pagination: state.pagination,
114-
}),
115-
)
105+
columns,
106+
get data() {
107+
return data()
108+
},
109+
})
116110

117-
table.state().pagination
111+
const pagination = createMemo(() => table.atoms.pagination.get())
112+
const pageIndex = createMemo(() => pagination().pageIndex)
113+
114+
const tableStateJson = createMemo(() =>
115+
JSON.stringify(table.store.get(), null, 2),
116+
)
118117
```
119118

120-
You can use the selected state in `createMemo`, JSX, or other Solid computations. Those computations update when the selected state changes.
119+
You can use atom reads directly in JSX too:
120+
121+
```tsx
122+
<span>
123+
Page {table.atoms.pagination.get().pageIndex + 1} of {table.getPageCount()}
124+
</span>
125+
```
121126

122127
#### Fine-grained Updates with table.Subscribe
123128

124-
Use `table.Subscribe` when you want a specific part of the Solid tree to subscribe to a selected table state value. The child function receives a Solid accessor.
129+
Use `table.Subscribe` when you want a specific part of the Solid tree to create a reactive render boundary. Its child function receives `table.atoms`, and Solid tracks only the atom reads used inside that child.
125130

126-
Without a `source` prop, `table.Subscribe` subscribes to `table.store` and requires a selector. With a `source` prop, it can subscribe directly to one atom or store.
131+
```tsx
132+
<table.Subscribe>
133+
{(atoms) => {
134+
void atoms.columnFilters.get()
135+
void atoms.globalFilter.get()
136+
void atoms.pagination.get()
137+
138+
return (
139+
<tbody>
140+
<For each={table.getRowModel().rows}>
141+
{(row) => <tr>{/* ... */}</tr>}
142+
</For>
143+
</tbody>
144+
)
145+
}}
146+
</table.Subscribe>
147+
```
127148

128149
```tsx
129-
<table.Subscribe
130-
selector={(state) => ({
131-
columnFilters: state.columnFilters,
132-
globalFilter: state.globalFilter,
133-
pagination: state.pagination,
134-
})}
135-
>
136-
{() => (
150+
<table.Subscribe>
151+
{(atoms) => (
137152
<tbody>
138153
<For each={table.getRowModel().rows}>
139-
{(row) => <tr>{/* ... */}</tr>}
154+
{(row) => {
155+
const isSelected = () => atoms.rowSelection.get()[row.id]
156+
157+
return (
158+
<tr>
159+
<td>
160+
<input
161+
type="checkbox"
162+
checked={!!isSelected()}
163+
onChange={row.getToggleSelectedHandler()}
164+
/>
165+
</td>
166+
</tr>
167+
)
168+
}}
140169
</For>
141170
</tbody>
142171
)}
143172
</table.Subscribe>
144173
```
145174

146-
```tsx
147-
<table.Subscribe
148-
source={table.atoms.rowSelection}
149-
selector={(rowSelection) => rowSelection[row.id]}
150-
>
151-
{(isSelected) => (
152-
<input
153-
type="checkbox"
154-
checked={!!isSelected()}
155-
onChange={row.getToggleSelectedHandler()}
156-
/>
157-
)}
158-
</table.Subscribe>
159-
```
160-
161175
### Setting Table State
162176

163177
You should almost never need to set table state directly. TanStack Table features expose dedicated APIs for interacting with their state, and those APIs are the safest way to make changes.
@@ -232,11 +246,11 @@ Slice reset APIs like `resetPagination()` update through that feature's state up
232246

233247
### Controlled State
234248

235-
If you need easy access to table state in other parts of your application, you can control individual state slices. In v9, external atoms are the recommended way to do this because they preserve the atomic state model and Solid can update computations that read only the relevant slices.
249+
If you need easy access to table state in other parts of your application, you can control individual state slices. In Solid, use native signals with `state` plus `on[State]Change` when you want Solid to own the slice. Use external TanStack Store atoms when you already want app-level atom sharing or direct atom subscriptions outside the table.
236250

237251
#### External Atoms
238252

239-
Use external atoms when the app should own one or more table state slices. Create stable writable atoms with `createAtom`, pass them to `atoms`, and subscribe to them with `useSelector` anywhere else in your app.
253+
Use external atoms when the app should own one or more table state slices as TanStack Store atoms. Create stable writable atoms with `createAtom`, pass them to `atoms`, and subscribe to them with `useSelector` anywhere else in your app. `@tanstack/solid-store` is only needed by your app if you choose this pattern; the Solid table adapter itself uses Solid-native reactivity.
240254

241255
```tsx
242256
import { createAtom, useSelector } from '@tanstack/solid-store'
@@ -284,7 +298,7 @@ When using the `atoms` option for a slice, you do not need to add the matching `
284298

285299
#### External State
286300

287-
The classic `state` plus `on[State]Change` pattern is still supported. This can be convenient for simple integrations or when migrating v8 code, but it is less atomic than external atoms.
301+
Use `state` plus `on[State]Change` when Solid signals should own a table state slice.
288302

289303
```tsx
290304
const [sorting, setSorting] = createSignal<SortingState>([])
@@ -316,7 +330,7 @@ const table = createTable({
316330
})
317331
```
318332

319-
The v8-style `onStateChange` option is no longer part of the v9 `createTable` state model. v9 encourages keeping table state slices atomic and separated for performance.
333+
Use the per-slice `on[State]Change` callbacks to keep controlled table state slices atomic and separated.
320334

321335
##### On State Change Callbacks
322336

0 commit comments

Comments
 (0)