From ab8e31871ec5e34631d849c5ada09a91cab161b7 Mon Sep 17 00:00:00 2001 From: Ola Alsaker Date: Sat, 3 Aug 2024 23:29:54 +0200 Subject: [PATCH] feat: add support for reactivity in Vue-adapter (#5687) * feat: add support for reactive data in Vue-adapter * docs: update example to use reactivity * add new in 8 20 callout to new docs * ci: apply automated fixes --------- Co-authored-by: Kevin Van Cott Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- docs/framework/vue/guide/table-state.md | 40 ++++++++++--- examples/vue/column-ordering/src/App.vue | 3 +- examples/vue/column-pinning/src/App.vue | 6 +- packages/vue-table/src/index.ts | 74 ++++++++++++++++++------ 4 files changed, 96 insertions(+), 27 deletions(-) diff --git a/docs/framework/vue/guide/table-state.md b/docs/framework/vue/guide/table-state.md index ad76d8e7b8..e8f682ea97 100644 --- a/docs/framework/vue/guide/table-state.md +++ b/docs/framework/vue/guide/table-state.md @@ -13,9 +13,7 @@ You do not need to set up anything special in order for the table state to work. ```ts const table = useVueTable({ columns, - get data() { - return data.value - }, + data: dataRef, // Reactive data support //... }) @@ -23,6 +21,36 @@ console.log(table.getState()) //access the entire internal state console.log(table.getState().rowSelection) //access just the row selection state ``` +### Using Reactive Data + +> **New in v8.20.0** + +The `useVueTable` hook now supports reactive data. This means you can pass a Vue `ref` or `computed` containing your data to the `data`-option. The table will automatically react to changes in the data. + +```ts +const columns = [ + { accessor: 'id', Header: 'ID' }, + { accessor: 'name', Header: 'Name' } +] + +const dataRef = ref([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' } +]) + +const table = useVueTable({ + columns, + data: dataRef, // Pass the reactive data ref +}) + +// Later, updating dataRef will automatically update the table +dataRef.value = [ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Doe' } +] +``` + ### Custom Initial State If all you need to do for certain states is customize their initial default values, you still do not need to manage any of the state yourself. You can simply set values in the `initialState` option of the table instance. @@ -126,9 +154,7 @@ const table = useVueTable({ get columns() { return columns.value }, - get data() { - return data.value - }, + data, //... Note: `state` values are NOT passed in yet }) @@ -201,4 +227,4 @@ const sorting = ref([ desc: true, } ]) -``` \ No newline at end of file +``` diff --git a/examples/vue/column-ordering/src/App.vue b/examples/vue/column-ordering/src/App.vue index 7cd177465f..38b9aa6256 100644 --- a/examples/vue/column-ordering/src/App.vue +++ b/examples/vue/column-ordering/src/App.vue @@ -83,7 +83,8 @@ const table = useVueTable({ }, onColumnOrderChange: order => { - columnOrder.value = order + columnOrder.value = + order instanceof Function ? order(columnOrder.value) : order }, getCoreRowModel: getCoreRowModel(), debugTable: true, diff --git a/examples/vue/column-pinning/src/App.vue b/examples/vue/column-pinning/src/App.vue index cb2c4d8420..f3a64cee67 100644 --- a/examples/vue/column-pinning/src/App.vue +++ b/examples/vue/column-pinning/src/App.vue @@ -94,10 +94,12 @@ const table = useVueTable({ }, onColumnOrderChange: order => { - columnOrder.value = order + columnOrder.value = + order instanceof Function ? order(columnOrder.value) : order }, onColumnPinningChange: pinning => { - columnPinning.value = pinning() + columnPinning.value = + pinning instanceof Function ? pinning(columnPinning.value) : pinning }, getCoreRowModel: getCoreRowModel(), debugTable: true, diff --git a/packages/vue-table/src/index.ts b/packages/vue-table/src/index.ts index 5b342de11b..1c3c4c596f 100755 --- a/packages/vue-table/src/index.ts +++ b/packages/vue-table/src/index.ts @@ -4,11 +4,33 @@ import { TableOptionsResolved, RowData, } from '@tanstack/table-core' -import { h, watchEffect, ref, defineComponent } from 'vue' +import { + h, + watchEffect, + ref, + defineComponent, + isRef, + unref, + MaybeRef, +} from 'vue' import { mergeProxy } from './merge-proxy' export * from '@tanstack/table-core' +type TableOptionsWithReactiveData = Omit< + TableOptions, + 'data' +> & { + data: MaybeRef +} + +type TableOptionsResolvedWithReactiveData = Omit< + TableOptionsResolved, + 'data' +> & { + data: MaybeRef +} + export const FlexRender = defineComponent({ props: ['render', 'props'], setup: (props: { render: any; props: any }) => { @@ -26,24 +48,32 @@ export const FlexRender = defineComponent({ }) export function useVueTable( - options: TableOptions + options: TableOptionsWithReactiveData ) { - const resolvedOptions: TableOptionsResolved = mergeProxy( - { - state: {}, // Dummy state - onStateChange: () => {}, // noop - renderFallbackValue: null, - mergeOptions( - defaultOptions: TableOptions, - options: TableOptions - ) { - return mergeProxy(defaultOptions, options) + const resolvedOptions: TableOptionsResolvedWithReactiveData = + mergeProxy( + { + state: {}, // Dummy state + onStateChange: () => {}, // noop + renderFallbackValue: null, + mergeOptions( + defaultOptions: TableOptions, + options: TableOptions + ) { + return mergeProxy(defaultOptions, options) + }, }, - }, - options - ) + options + ) + + // Add support for reactivity + if (isRef(options.data)) { + resolvedOptions.data = unref(options.data) + } - const table = createTable(resolvedOptions) + const table = createTable( + resolvedOptions as TableOptionsResolved + ) // can't use `reactive` because update needs to be immutable const state = ref(table.initialState) @@ -53,7 +83,7 @@ export function useVueTable( get: (_, prop) => state.value[prop as keyof typeof state.value], }) - return mergeProxy(prev, options, { + const newOptions = mergeProxy(prev, options, { // merge the initialState and `options.state` // create a new proxy on each `setOptions` call // and get the value from state on each property access @@ -70,6 +100,16 @@ export function useVueTable( options.onStateChange?.(updater) }, }) + + // Add support for reactivity + if (isRef(options.data)) { + return { + ...newOptions, + data: unref(options.data), + } + } + + return newOptions }) })