feat: add new Guide for renderingLargeData
This commit is contained in:
parent
b09910fb2e
commit
79a344626e
|
|
@ -23,11 +23,6 @@ const examples = [
|
|||
href: '/examples/tasks',
|
||||
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/tasks',
|
||||
},
|
||||
{
|
||||
name: 'Tasks (Big Data)',
|
||||
href: '/examples/big-data',
|
||||
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/big-data',
|
||||
},
|
||||
{
|
||||
name: 'Playground',
|
||||
href: '/examples/playground',
|
||||
|
|
|
|||
|
|
@ -353,6 +353,16 @@ export const docsConfig: DocsConfig = {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Guides',
|
||||
items: [
|
||||
{
|
||||
title: 'Render Large Data',
|
||||
href: '/docs/guides/rendering-large-data',
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
|||
29
apps/www/src/content/docs/guides/rendering-large-data.md
Normal file
29
apps/www/src/content/docs/guides/rendering-large-data.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
title: Rendering Large Data
|
||||
description: In some cases, you may need to render a large amount of data. This can be done using the useVirtualList Component from VueUse library to render only the visible items. This can help to improve performance.
|
||||
sidebar: false
|
||||
---
|
||||
|
||||
## How to render large data
|
||||
|
||||
When you have a large amount of data to render, you can use the [useVirtualList](https://vueuse.org/core/useVirtualList/#usevirtuallist) Component from [VueUse](https://vueuse.org/) library to render only the visible items. This can help to improve performance.
|
||||
|
||||
`useVirtualList` waiting for a `MaybeRef<T[]>` so firstly you need to wrap your data with `ref` or `computed` function. So we will convert our `table.getRowModel().rows` to `computed` function.
|
||||
|
||||
<<< @/examples/big-data/components/DataTable.vue#tableRows{ts}
|
||||
|
||||
Next step is to create a `useVirtualList` instance and pass our `tableRows` to it. For better experience list elements must be same height, which you define inside `itemHeight` property. `overscan` property is used to define how many items should be rendered outside of the visible area.
|
||||
|
||||
<<< @/examples/big-data/components/DataTable.vue#useVirtualList{2-3 ts}
|
||||
|
||||
## Example
|
||||
|
||||
Here is an example of how to use `useVirtualList` to render a large amount of data. For test purposes, we will use 2000 rows for our table, you can change statuses, priorities, and view to see speed difference.
|
||||
|
||||
<script setup>
|
||||
import BigDataExample from "@/examples/big-data/Example.vue"
|
||||
</script>
|
||||
|
||||
<Suspense>
|
||||
<BigDataExample />
|
||||
</Suspense>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<script setup>
|
||||
import BigDataExample from "@/examples/big-data/Example.vue"
|
||||
</script>
|
||||
|
||||
<BigDataExample />
|
||||
|
|
@ -1,36 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import tasks from './data/tasks.json'
|
||||
import DataTable from './components/DataTable.vue'
|
||||
import UserNav from './components/UserNav.vue'
|
||||
import { columns } from './components/columns'
|
||||
|
||||
const response = await fetch('https://api.json-generator.com/templates/NttPDOzDwSsS/data?access_token=xi78iyv3ez1qwmm9pgou7r5mbqxfxrfmdzcps0hm')
|
||||
const tasks = await response.json()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="md:hidden">
|
||||
<VPImage
|
||||
alt="Tasks"
|
||||
width="1280"
|
||||
height="1214" class="block" :image="{
|
||||
dark: '/examples/tasks-dark.png',
|
||||
light: '/examples/tasks-light.png',
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="hidden h-full flex-1 flex-col space-y-8 p-8 md:flex">
|
||||
<div class="flex items-center justify-between space-y-2">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold tracking-tight">
|
||||
Welcome back!
|
||||
</h2>
|
||||
<p class="text-muted-foreground">
|
||||
Here's a list of your tasks for this month!
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<UserNav />
|
||||
</div>
|
||||
</div>
|
||||
<DataTable :data="tasks" :columns="columns" />
|
||||
</div>
|
||||
<DataTable :data="tasks" :columns="columns" />
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -70,12 +70,16 @@ const table = useVueTable({
|
|||
},
|
||||
})
|
||||
|
||||
// #region tableRows
|
||||
const tableRows = computed(() => table.getRowModel().rows)
|
||||
// #endregion tableRows
|
||||
|
||||
// #region useVirtualList
|
||||
const { list, containerProps, wrapperProps } = useVirtualList(tableRows, {
|
||||
itemHeight: 49,
|
||||
overscan: 15,
|
||||
})
|
||||
// #endregion useVirtualList
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -85,7 +89,7 @@ const { list, containerProps, wrapperProps } = useVirtualList(tableRows, {
|
|||
<Table v-bind="wrapperProps">
|
||||
<TableHeader style="height: 49px">
|
||||
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
||||
<TableHead v-for="header in headerGroup.headers" :key="header.id">
|
||||
<TableHead v-for="header in headerGroup.headers" :key="header.id" class="sticky top-0 bg-black z-10 border-b">
|
||||
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header" :props="header.getContext()" />
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import ArrowDownIcon from '~icons/radix-icons/arrow-down'
|
|||
import ArrowUpIcon from '~icons/radix-icons/arrow-up'
|
||||
import CaretSortIcon from '~icons/radix-icons/caret-sort'
|
||||
import EyeNoneIcon from '~icons/radix-icons/eye-none'
|
||||
import ResetIcon from '~icons/radix-icons/reset'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
|
|
@ -59,6 +60,10 @@ export default {
|
|||
<EyeNoneIcon class="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
|
||||
Hide
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem v-if="column.getIsSorted()" @click="column.clearSorting()">
|
||||
<ResetIcon class="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
|
||||
Reset
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ const isFiltered = computed(() => props.table.getState().columnFilters.length >
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex flex-1 items-center space-x-2">
|
||||
<div class="flex items-start justify-between flex-wrap">
|
||||
<div class="flex flex-1 items-center gap-2 flex-wrap">
|
||||
<Input
|
||||
placeholder="Filter tasks..."
|
||||
:model-value="(table.getColumn('title')?.getFilterValue() as string) ?? ''"
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export const columns: ColumnDef<Task>[] = [
|
|||
|
||||
return h('div', { class: 'flex space-x-2' }, [
|
||||
label && h(Badge, { variant: 'outline' }, label.label),
|
||||
h('span', { class: 'max-w-[500px] truncate font-medium' }, row.getValue('title')),
|
||||
h('span', { class: 'max-w-[180px] truncate font-medium' }, row.getValue('title')),
|
||||
])
|
||||
},
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -40,7 +40,7 @@ defineProps<DataTablePaginationProps>()
|
|||
<SelectValue :placeholder="`${table.getState().pagination.pageSize}`" />
|
||||
</SelectTrigger>
|
||||
<SelectContent side="top">
|
||||
<SelectItem v-for="pageSize in [10, 20, 30, 40, 50, 100, 1000]" :key="pageSize" :value="`${pageSize}`">
|
||||
<SelectItem v-for="pageSize in [10, 20, 30, 40, 50]" :key="pageSize" :value="`${pageSize}`">
|
||||
{{ pageSize }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user