Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for reactivity in Vue-adapter #5687

Merged
merged 5 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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