fix(Table): improve data reactivity (#3967)

Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
Guillaume REMBERT
2025-04-24 10:10:37 +00:00
committed by GitHub
parent b4f8ac7ff7
commit 6e27304d8c
2 changed files with 36 additions and 5 deletions

View File

@@ -143,6 +143,8 @@ const data = ref<Payment[]>([{
amount: 567
}])
const currentID = ref(4601)
const columns: TableColumn<Payment>[] = [{
id: 'select',
header: ({ table }) => h(UCheckbox, {
@@ -277,8 +279,19 @@ const pagination = ref({
pageSize: 10
})
function addElement() {
data.value.unshift({
id: currentID.value.toString(),
date: new Date().toISOString(),
status: 'paid',
email: 'new@example.com',
amount: Math.random() * 1000
})
currentID.value++
}
function randomize() {
data.value = [...data.value].sort(() => Math.random() - 0.5)
data.value = data.value.sort(() => Math.random() - 0.5)
}
function onSelect(row: TableRow<Payment>) {
@@ -303,6 +316,7 @@ onMounted(() => {
/>
<UButton color="neutral" label="Randomize" @click="randomize" />
<UButton color="neutral" label="Add element" @click="addElement" />
<UDropdownMenu
:items="table?.tableApi?.getAllColumns().filter(column => column.getCanHide()).map(column => ({

View File

@@ -1,6 +1,6 @@
<!-- eslint-disable vue/block-tag-newline -->
<script lang="ts">
import type { Ref } from 'vue'
import type { Ref, WatchOptions } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import type { Cell, Header, RowData, TableMeta } from '@tanstack/table-core'
import type {
@@ -97,6 +97,13 @@ export interface TableProps<T extends TableData> extends TableOptions<T> {
* @defaultValue 'carousel'
*/
loadingAnimation?: Table['variants']['loadingAnimation']
/**
* Use the `watchOptions` prop to customize reactivity (for ex: disable deep watching for changes in your data or limiting the max traversal depth). This can improve performance by reducing unnecessary re-renders, but it should be used with caution as it may lead to unexpected behavior if not managed properly.
* @link [API Docs](https://vuejs.org/api/options-state.html#watch)
* @link [Guide](https://vuejs.org/guide/essentials/watchers.html)
* @defaultValue { deep: true }
*/
watchOptions?: WatchOptions
/**
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#table-options)
* @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)
@@ -175,7 +182,7 @@ export type TableSlots<T> = {
</script>
<script setup lang="ts" generic="T extends TableData">
import { computed, ref } from 'vue'
import { computed, ref, watch } from 'vue'
import { Primitive } from 'reka-ui'
import { upperFirst } from 'scule'
import { FlexRender, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getExpandedRowModel, useVueTable } from '@tanstack/vue-table'
@@ -184,13 +191,17 @@ import { useAppConfig } from '#imports'
import { useLocale } from '../composables/useLocale'
import { tv } from '../utils/tv'
const props = defineProps<TableProps<T>>()
const props = withDefaults(defineProps<TableProps<T>>(), {
watchOptions: () => ({
deep: true
})
})
const slots = defineSlots<TableSlots<T>>()
const { t } = useLocale()
const appConfig = useAppConfig() as Table['AppConfig']
const data = computed(() => props.data ?? [])
const data = ref(props.data ?? []) as Ref<T[]>
const columns = computed<TableColumn<T>[]>(() => props.columns ?? Object.keys(data.value[0] ?? {}).map((accessorKey: string) => ({ accessorKey, header: upperFirst(accessorKey) })))
const meta = computed(() => props.meta ?? {})
@@ -314,6 +325,12 @@ function handleRowSelect(row: TableRow<T>, e: Event) {
props.onSelect(row, e)
}
watch(
() => props.data, () => {
data.value = props.data ? [...props.data] : []
}, props.watchOptions
)
defineExpose({
tableRef,
tableApi