Skip to content

Commit

Permalink
feat: add support for reactivity in Vue-adapter (#5687)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 3, 2024
1 parent f8a018d commit ab8e318
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 27 deletions.
40 changes: 33 additions & 7 deletions docs/framework/vue/guide/table-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,44 @@ 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
//...
})

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.
Expand Down Expand Up @@ -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
})
Expand Down Expand Up @@ -201,4 +227,4 @@ const sorting = ref<SortingState[]>([
desc: true,
}
])
```
```
3 changes: 2 additions & 1 deletion examples/vue/column-ordering/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions examples/vue/column-pinning/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
74 changes: 57 additions & 17 deletions packages/vue-table/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<TData extends RowData> = Omit<
TableOptions<TData>,
'data'
> & {
data: MaybeRef<TData[]>
}

type TableOptionsResolvedWithReactiveData<TData extends RowData> = Omit<
TableOptionsResolved<TData>,
'data'
> & {
data: MaybeRef<TData[]>
}

export const FlexRender = defineComponent({
props: ['render', 'props'],
setup: (props: { render: any; props: any }) => {
Expand All @@ -26,24 +48,32 @@ export const FlexRender = defineComponent({
})

export function useVueTable<TData extends RowData>(
options: TableOptions<TData>
options: TableOptionsWithReactiveData<TData>
) {
const resolvedOptions: TableOptionsResolved<TData> = mergeProxy(
{
state: {}, // Dummy state
onStateChange: () => {}, // noop
renderFallbackValue: null,
mergeOptions(
defaultOptions: TableOptions<TData>,
options: TableOptions<TData>
) {
return mergeProxy(defaultOptions, options)
const resolvedOptions: TableOptionsResolvedWithReactiveData<TData> =
mergeProxy(
{
state: {}, // Dummy state
onStateChange: () => {}, // noop
renderFallbackValue: null,
mergeOptions(
defaultOptions: TableOptions<TData>,
options: TableOptions<TData>
) {
return mergeProxy(defaultOptions, options)
},
},
},
options
)
options
)

// Add support for reactivity
if (isRef(options.data)) {
resolvedOptions.data = unref(options.data)
}

const table = createTable<TData>(resolvedOptions)
const table = createTable<TData>(
resolvedOptions as TableOptionsResolved<TData>
)
// can't use `reactive` because update needs to be immutable
const state = ref(table.initialState)

Expand All @@ -53,7 +83,7 @@ export function useVueTable<TData extends RowData>(
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
Expand All @@ -70,6 +100,16 @@ export function useVueTable<TData extends RowData>(
options.onStateChange?.(updater)
},
})

// Add support for reactivity
if (isRef(options.data)) {
return {
...newOptions,
data: unref(options.data),
}
}

return newOptions
})
})

Expand Down

0 comments on commit ab8e318

Please sign in to comment.