From 8712031b1ed28bd1cbc19136e1179c6226e13af4 Mon Sep 17 00:00:00 2001 From: Kevin Van Cott Date: Tue, 6 Oct 2026 15:48:55 -0500 Subject: [PATCH] fix(adapters): Deprecate Solid and Vue table.Subscribe --- .changeset/mighty-pans-arrive.md | 5 ++ .changeset/whole-horses-sink.md | 5 ++ .../framework/solid/guide/column-filtering.md | 2 +- .../framework/solid/guide/global-filtering.md | 2 +- docs/framework/solid/guide/migrating.md | 24 +++--- docs/framework/solid/guide/pagination.md | 2 +- docs/framework/solid/guide/row-selection.md | 2 +- docs/framework/solid/guide/sorting.md | 2 +- docs/framework/solid/guide/table-state.md | 66 ++++++----------- .../solid/reference/functions/createTable.md | 5 +- .../reference/functions/createTableHook.md | 6 +- .../reference/interfaces/AppTableComponent.md | 4 +- .../reference/type-aliases/SolidTable.md | 12 ++- docs/framework/vue/guide/cell-selection.md | 2 +- docs/framework/vue/guide/column-faceting.md | 2 +- docs/framework/vue/guide/column-filtering.md | 2 +- docs/framework/vue/guide/column-resizing.md | 2 +- docs/framework/vue/guide/global-filtering.md | 2 +- docs/framework/vue/guide/migrating.md | 18 ++--- docs/framework/vue/guide/pagination.md | 2 +- docs/framework/vue/guide/row-selection.md | 2 +- docs/framework/vue/guide/sorting.md | 2 +- docs/framework/vue/guide/table-state.md | 60 +++++---------- .../vue/reference/functions/useTable.md | 9 ++- .../vue/reference/type-aliases/VueTable.md | 14 ++-- .../solid/spreadsheet/src/Spreadsheet.tsx | 74 ++++++++----------- .../skills/migrate-v8-to-v9/SKILL.md | 2 +- .../references/adapter-migration.md | 8 +- .../solid-table/skills/table-state/SKILL.md | 2 +- packages/solid-table/src/createTable.ts | 9 ++- packages/solid-table/src/createTableHook.tsx | 22 ++---- .../references/create-table-hook.md | 20 +---- .../skills/migrate-v8-to-v9/SKILL.md | 2 +- .../references/adapter-migration.md | 2 +- .../vue-table/skills/table-state/SKILL.md | 4 +- .../table-state/references/reactivity.md | 32 ++------ packages/vue-table/src/useTable.ts | 11 ++- 37 files changed, 178 insertions(+), 264 deletions(-) create mode 100644 .changeset/mighty-pans-arrive.md create mode 100644 .changeset/whole-horses-sink.md diff --git a/.changeset/mighty-pans-arrive.md b/.changeset/mighty-pans-arrive.md new file mode 100644 index 0000000000..e6ddcf1808 --- /dev/null +++ b/.changeset/mighty-pans-arrive.md @@ -0,0 +1,5 @@ +--- +'@tanstack/solid-table': patch +--- + +Deprecate table.Subscribe in the Solid adapter. Read table APIs or atoms directly inside JSX, createMemo, or createEffect; Solid tracks these reads natively. Keep the wrapper for compatibility and update examples and guidance to use direct reads. diff --git a/.changeset/whole-horses-sink.md b/.changeset/whole-horses-sink.md new file mode 100644 index 0000000000..7c7df2d71e --- /dev/null +++ b/.changeset/whole-horses-sink.md @@ -0,0 +1,5 @@ +--- +'@tanstack/vue-table': patch +--- + +Deprecate table.Subscribe in the Vue adapter. Read table APIs or atoms in native Vue reactive contexts, and use a child component when a separate render boundary is needed. Keep the wrapper for compatibility and update migration guidance. diff --git a/docs/framework/solid/guide/column-filtering.md b/docs/framework/solid/guide/column-filtering.md index 40362d45ee..c17cd32ac0 100644 --- a/docs/framework/solid/guide/column-filtering.md +++ b/docs/framework/solid/guide/column-filtering.md @@ -133,7 +133,7 @@ Since the column filter state is an array of objects, you can have multiple colu #### Accessing Column Filter State -In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.columnFilters.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, `createEffect`, or `table.Subscribe`). In event handlers or other untracked code, the same call simply returns the current value. +In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.columnFilters.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, or `createEffect`). In event handlers or other untracked code, the same call simply returns the current value. ```tsx const table = createTable({ diff --git a/docs/framework/solid/guide/global-filtering.md b/docs/framework/solid/guide/global-filtering.md index f96db6ebe5..83762cb88f 100644 --- a/docs/framework/solid/guide/global-filtering.md +++ b/docs/framework/solid/guide/global-filtering.md @@ -147,7 +147,7 @@ You can also define your own custom global filter function and pass it directly ### Global Filter State -The `globalFilter` state slice holds the current global filter value, usually a search string (the slice is typed as `any` so custom global filter functions can accept other value shapes). In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.globalFilter.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, `createEffect`, or `table.Subscribe`). In event handlers, the same call simply returns the current value. +The `globalFilter` state slice holds the current global filter value, usually a search string (the slice is typed as `any` so custom global filter functions can accept other value shapes). In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.globalFilter.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, or `createEffect`). In event handlers, the same call simply returns the current value. If you need access to the global filter state outside of the table, you can own the slice yourself. The recommended way in v9 is an external atom passed through the `atoms` table option. Atoms preserve fine-grained subscriptions, and the filter value can be used elsewhere (such as in a query key for server-side filtering) without making the table depend on component-local state. diff --git a/docs/framework/solid/guide/migrating.md b/docs/framework/solid/guide/migrating.md index 1d57ee11a1..6cbc086296 100644 --- a/docs/framework/solid/guide/migrating.md +++ b/docs/framework/solid/guide/migrating.md @@ -15,7 +15,7 @@ TanStack Table V9 delivers major performance improvements, hundreds of bug fixes ### 2. State Management Overhaul - **TanStack Store foundation**: State is backed by TanStack Store atoms with Solid-aware reactivity. -- **Solid-native reads**: Atom reads participate in Solid tracking when called inside JSX, `createMemo`, `createEffect`, or `table.Subscribe`. +- **Solid-native reads**: Atom reads participate in Solid tracking when called inside JSX, `createMemo`, or `createEffect`. - **External atoms**: Apps can own individual slices with atoms from `@tanstack/solid-store`. ### 3. Type-Safety Improvements @@ -295,12 +295,12 @@ Because these methods now live on the prototype, they also do not appear as own Solid v9 uses table atoms backed by Solid primitives. Prefer narrow atom reads or Solid memos over broad whole-state reads. -| Surface | Use | -| --------------------------- | --------------------------------------------------------------------------------------------- | -| `table.atoms..get()` | Narrow reactive reads inside Solid tracking scopes. | -| `table.store.get()` | Current full state snapshot. Use mostly for debug output or intentionally broad dependencies. | -| `table.Subscribe` | A Solid render boundary whose child reads the atoms it needs. | -| `table.baseAtoms.` | Internal writable atoms. Prefer feature APIs or external atoms. | +| Surface | Use | +| --------------------------- | ---------------------------------------------------------------------------------------------- | +| `table.atoms..get()` | Narrow reactive reads inside Solid tracking scopes. | +| `table.store.get()` | Current full state snapshot. Use mostly for debug output or intentionally broad dependencies. | +| `table.Subscribe` | Deprecated compatibility wrapper. Read table APIs or atoms directly in JSX, memos, or effects. | +| `table.baseAtoms.` | Internal writable atoms. Prefer feature APIs or external atoms. | ### Accessing State @@ -335,16 +335,16 @@ Atom reads can also be used directly in JSX: ``` -### Fine-grained Updates with `table.Subscribe` +### Replace `table.Subscribe` -`table.Subscribe` passes `table.atoms` to its child function. As with any Solid component, the child function body runs once and is untracked, so read atoms inside JSX expressions (or thunks called from JSX) for Solid to track them. +`table.Subscribe` is deprecated. It only passes `table.atoms` to its child function and creates no subscription or tracking scope. Remove the wrapper and read atoms directly inside JSX, `createMemo`, or `createEffect`: ```tsx - - {(atoms) => Page {atoms.pagination.get().pageIndex + 1}} - +Page {table.atoms.pagination.get().pageIndex + 1} ``` +Solid tracks these reads natively. Component bodies run once, so keep reactive reads inside a tracked scope. + ### Controlled State The v8-style `state` + `on[State]Change` controlled state patterns still work and remain convenient for simple integrations. For new v9 code, prefer owning state slices with external atoms (see [External Atoms](#external-atoms) below), which give you fine-grained subscriptions without mirroring state through signals. If you do control state with signals, use getters in `state` so Solid tracks the current signal values. diff --git a/docs/framework/solid/guide/pagination.md b/docs/framework/solid/guide/pagination.md index 0f74f04c50..73297fbd05 100644 --- a/docs/framework/solid/guide/pagination.md +++ b/docs/framework/solid/guide/pagination.md @@ -222,7 +222,7 @@ The `pagination` state is an object that contains the following properties: - `pageIndex`: The current page index (zero-based). - `pageSize`: The current page size. -In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.pagination.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, `createEffect`, or `table.Subscribe`). In event handlers, the same call simply returns the current value. +In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.pagination.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, or `createEffect`). In event handlers, the same call simply returns the current value. If you need access to the `pagination` state outside of the table (a server-side query key is the most common case), you can own the slice yourself. The recommended way in v9 is an external atom passed through the `atoms` table option. Atoms preserve fine-grained subscriptions, and the pagination value can be used in a query key without making the table depend on component-local state. diff --git a/docs/framework/solid/guide/row-selection.md b/docs/framework/solid/guide/row-selection.md index 9e9ef99294..b7588da736 100644 --- a/docs/framework/solid/guide/row-selection.md +++ b/docs/framework/solid/guide/row-selection.md @@ -52,7 +52,7 @@ console.log(table.getFilteredSelectedRowModel().rows) //get filtered client-side console.log(table.getGroupedSelectedRowModel().rows) //get grouped client-side selected rows ``` -In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.rowSelection.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, `createEffect`, or `table.Subscribe`). In event handlers or other untracked code, the same call simply returns the current value. +In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.rowSelection.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, or `createEffect`). In event handlers or other untracked code, the same call simply returns the current value. > [!NOTE] > If you are using `manualPagination`, be aware that the `getSelectedRowModel` API will only return selected rows on the current page because table row models can only generate rows based on the `data` that is passed in. Row selection state, however, can contain row ids that are not present in the `data` array just fine. diff --git a/docs/framework/solid/guide/sorting.md b/docs/framework/solid/guide/sorting.md index a837f7c356..b555f03aee 100644 --- a/docs/framework/solid/guide/sorting.md +++ b/docs/framework/solid/guide/sorting.md @@ -68,7 +68,7 @@ Since the sorting state is an array, it is possible to sort by multiple columns #### Accessing Sorting State -In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.sorting.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, `createEffect`, or `table.Subscribe`). In event handlers or other untracked code, the same call simply returns the current value. `table.store.get()` returns a current full-state snapshot, useful for debugging. +In Solid, the table's state atoms are backed by Solid signals, so `table.atoms.sorting.get()` is a reactive read when called inside a tracked scope (JSX, `createMemo`, or `createEffect`). In event handlers or other untracked code, the same call simply returns the current value. `table.store.get()` returns a current full-state snapshot, useful for debugging. ```tsx const table = createTable({ diff --git a/docs/framework/solid/guide/table-state.md b/docs/framework/solid/guide/table-state.md index 3273a99b15..adfd0ceae9 100644 --- a/docs/framework/solid/guide/table-state.md +++ b/docs/framework/solid/guide/table-state.md @@ -71,7 +71,7 @@ There are two different questions when reading table state: - Do you only need the current value? - Or should a Solid computation update when that value changes? -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`. +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(...)`, or `createEffect(...)`. #### Reading State @@ -120,56 +120,32 @@ You can use atom reads directly in JSX too: ``` -#### Fine-grained Updates with table.Subscribe +#### Fine-grained updates -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`. As with any Solid component, the child function body runs once and is untracked, so perform atom reads inside JSX expressions or in thunks called from JSX; Solid tracks only those reads. +Read table APIs and atoms directly inside JSX. Solid tracks the reads and updates the expressions that depend on them. For derived values outside JSX, use `createMemo` or an accessor called from JSX. -```tsx - - {(atoms) => { - // a thunk: the reads run (and track) when JSX calls it, not in the body - const rows = () => { - atoms.columnFilters.get() - atoms.globalFilter.get() - atoms.pagination.get() - return table.getRowModel().rows - } - - return ( - - {(row) => {/* ... */}} - - ) - }} - -``` +`table.Subscribe` is deprecated. It only passes atoms to its child function and creates no subscription or tracking scope. Remove the wrapper and replace the child function's `atoms` parameter with `table.atoms`. ```tsx - - {(atoms) => ( - - - {(row) => { - const isSelected = () => atoms.rowSelection.get()[row.id] - - return ( - - - - - - ) - }} - - - )} - + + + {(row) => ( + + + + + + )} + + ``` +Keep reactive reads inside JSX, memos, or effects. Reading an atom into a plain variable in a component body captures its current value and does not track updates. + ### Setting Table State 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. diff --git a/docs/framework/solid/reference/functions/createTable.md b/docs/framework/solid/reference/functions/createTable.md index a1c36de618..1bf715aa31 100644 --- a/docs/framework/solid/reference/functions/createTable.md +++ b/docs/framework/solid/reference/functions/createTable.md @@ -9,13 +9,14 @@ title: createTable function createTable(tableOptions): SolidTable; ``` -Defined in: [createTable.ts:61](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTable.ts#L61) +Defined in: [createTable.ts:64](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTable.ts#L64) Creates a Solid table instance backed by Solid-aware TanStack Store atoms. Table APIs and atom reads participate in Solid dependency tracking, so computations that read a specific slice can update without invalidating -unrelated UI. Use `table.Subscribe` to create atom-tracked render boundaries. +unrelated UI. Read table APIs or atoms inside JSX, `createMemo`, or +`createEffect` to track updates. ## Type Parameters diff --git a/docs/framework/solid/reference/functions/createTableHook.md b/docs/framework/solid/reference/functions/createTableHook.md index f3e7faa9bc..884bff4a15 100644 --- a/docs/framework/solid/reference/functions/createTableHook.md +++ b/docs/framework/solid/reference/functions/createTableHook.md @@ -9,7 +9,7 @@ title: createTableHook function createTableHook(__namedParameters): CreateTableHookResult; ``` -Defined in: [createTableHook.tsx:571](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L571) +Defined in: [createTableHook.tsx:569](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L569) Creates a custom table hook with pre-bound components for composition. @@ -81,9 +81,7 @@ const columnHelper = createAppColumnHelper() function PaginationControls() { const table = useTableContext() // TFeatures already known! return ( - - {(atoms) => Page {atoms.pagination.get().pageIndex + 1}} - + Page {table.atoms.pagination.get().pageIndex + 1} ) } diff --git a/docs/framework/solid/reference/interfaces/AppTableComponent.md b/docs/framework/solid/reference/interfaces/AppTableComponent.md index f8989c0a19..4176aba659 100644 --- a/docs/framework/solid/reference/interfaces/AppTableComponent.md +++ b/docs/framework/solid/reference/interfaces/AppTableComponent.md @@ -7,7 +7,7 @@ title: AppTableComponent Defined in: [createTableHook.tsx:337](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L337) -Component type for AppTable - root wrapper with optional Subscribe +Component type for AppTable - root wrapper that provides table context ## Type Parameters @@ -21,7 +21,7 @@ AppTableComponent(props): Element; Defined in: [createTableHook.tsx:338](https://github.com/TanStack/table/blob/main/packages/solid-table/src/createTableHook.tsx#L338) -Component type for AppTable - root wrapper with optional Subscribe +Component type for AppTable - root wrapper that provides table context ## Parameters diff --git a/docs/framework/solid/reference/type-aliases/SolidTable.md b/docs/framework/solid/reference/type-aliases/SolidTable.md index 981d6d6fcb..521ec24727 100644 --- a/docs/framework/solid/reference/type-aliases/SolidTable.md +++ b/docs/framework/solid/reference/type-aliases/SolidTable.md @@ -31,15 +31,12 @@ rendering headers, cells, or footers with custom markup. Mirrors the ``` -### Subscribe() +### ~~Subscribe~~ ```ts Subscribe: (props) => JSX.Element; ``` -Creates a reactive render boundary. The child function reads the table -atoms it needs, so Solid only tracks those atom reads. - #### Parameters ##### props @@ -52,6 +49,13 @@ atoms it needs, so Solid only tracks those atom reads. `JSX.Element` +#### Deprecated + +Read table APIs or `table.atoms` directly inside JSX, +`createMemo`, or `createEffect`. Solid tracks those reads natively. +This compatibility wrapper only passes atoms to its child function; +it does not create a subscription or tracking scope. + ## Type Parameters ### TFeatures diff --git a/docs/framework/vue/guide/cell-selection.md b/docs/framework/vue/guide/cell-selection.md index eb63b0a44f..f1c373508f 100644 --- a/docs/framework/vue/guide/cell-selection.md +++ b/docs/framework/vue/guide/cell-selection.md @@ -36,7 +36,7 @@ The cell selection feature keeps track of spreadsheet-style rectangular selectio The table instance already manages the cell selection state for you. You can access the selection or values derived from it through a few APIs. -- `table.atoms.cellSelection.get()` - returns the current cell selection (reactive inside templates, `computed(...)`, `watch(...)`, and `table.Subscribe`; a plain snapshot elsewhere) +- `table.atoms.cellSelection.get()` - returns the current cell selection (reactive inside templates, `computed(...)`, `watch(...)` sources, and render functions; a plain snapshot elsewhere) - `getSelectedCellCount()` - returns how many cells are selected - `getSelectedCellIds()` - returns the ids of every selected cell - `getCellSelectionRowIds()` / `getCellSelectionColumnIds()` - returns the rows and columns the selection touches diff --git a/docs/framework/vue/guide/column-faceting.md b/docs/framework/vue/guide/column-faceting.md index a8f82de322..029b84909e 100644 --- a/docs/framework/vue/guide/column-faceting.md +++ b/docs/framework/vue/guide/column-faceting.md @@ -153,7 +153,7 @@ If you want each count to represent rows, make sure `getUniqueValues` returns ea ### Reactive Facet Controls in Vue -Read facet APIs inside a Vue reactive context such as `computed`, a template, or `table.Subscribe`. A filter component can derive its options from a stable `column` prop with `computed`. +Read facet APIs inside a Vue reactive context such as `computed`, a template, or a render function. A filter component can derive its options from a stable `column` prop with `computed`. ```vue