feat: add new Guide for renderingLargeData

This commit is contained in:
hrynevych.romann 2024-02-20 22:48:28 +02:00
parent b09910fb2e
commit 79a344626e
12 changed files with 57 additions and 25946 deletions

View File

@ -23,11 +23,6 @@ const examples = [
href: '/examples/tasks', href: '/examples/tasks',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/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', name: 'Playground',
href: '/examples/playground', href: '/examples/playground',

View File

@ -353,6 +353,16 @@ export const docsConfig: DocsConfig = {
}, },
], ],
}, },
{
title: 'Guides',
items: [
{
title: 'Render Large Data',
href: '/docs/guides/rendering-large-data',
items: [],
},
],
},
], ],
} }

View 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>

View File

@ -1,5 +0,0 @@
<script setup>
import BigDataExample from "@/examples/big-data/Example.vue"
</script>
<BigDataExample />

View File

@ -1,36 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import tasks from './data/tasks.json'
import DataTable from './components/DataTable.vue' import DataTable from './components/DataTable.vue'
import UserNav from './components/UserNav.vue'
import { columns } from './components/columns' 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> </script>
<template> <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&apos;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" /> <DataTable :data="tasks" :columns="columns" />
</div>
</template> </template>

View File

@ -70,12 +70,16 @@ const table = useVueTable({
}, },
}) })
// #region tableRows
const tableRows = computed(() => table.getRowModel().rows) const tableRows = computed(() => table.getRowModel().rows)
// #endregion tableRows
// #region useVirtualList
const { list, containerProps, wrapperProps } = useVirtualList(tableRows, { const { list, containerProps, wrapperProps } = useVirtualList(tableRows, {
itemHeight: 49, itemHeight: 49,
overscan: 15, overscan: 15,
}) })
// #endregion useVirtualList
</script> </script>
<template> <template>
@ -85,7 +89,7 @@ const { list, containerProps, wrapperProps } = useVirtualList(tableRows, {
<Table v-bind="wrapperProps"> <Table v-bind="wrapperProps">
<TableHeader style="height: 49px"> <TableHeader style="height: 49px">
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id"> <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()" /> <FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header" :props="header.getContext()" />
</TableHead> </TableHead>
</TableRow> </TableRow>

View File

@ -5,6 +5,7 @@ import ArrowDownIcon from '~icons/radix-icons/arrow-down'
import ArrowUpIcon from '~icons/radix-icons/arrow-up' import ArrowUpIcon from '~icons/radix-icons/arrow-up'
import CaretSortIcon from '~icons/radix-icons/caret-sort' import CaretSortIcon from '~icons/radix-icons/caret-sort'
import EyeNoneIcon from '~icons/radix-icons/eye-none' import EyeNoneIcon from '~icons/radix-icons/eye-none'
import ResetIcon from '~icons/radix-icons/reset'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/new-york/ui/button' 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" /> <EyeNoneIcon class="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
Hide Hide
</DropdownMenuItem> </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> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
</div> </div>

View File

@ -20,8 +20,8 @@ const isFiltered = computed(() => props.table.getState().columnFilters.length >
</script> </script>
<template> <template>
<div class="flex items-center justify-between"> <div class="flex items-start justify-between flex-wrap">
<div class="flex flex-1 items-center space-x-2"> <div class="flex flex-1 items-center gap-2 flex-wrap">
<Input <Input
placeholder="Filter tasks..." placeholder="Filter tasks..."
:model-value="(table.getColumn('title')?.getFilterValue() as string) ?? ''" :model-value="(table.getColumn('title')?.getFilterValue() as string) ?? ''"

View File

@ -34,7 +34,7 @@ export const columns: ColumnDef<Task>[] = [
return h('div', { class: 'flex space-x-2' }, [ return h('div', { class: 'flex space-x-2' }, [
label && h(Badge, { variant: 'outline' }, label.label), 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

View File

@ -40,7 +40,7 @@ defineProps<DataTablePaginationProps>()
<SelectValue :placeholder="`${table.getState().pagination.pageSize}`" /> <SelectValue :placeholder="`${table.getState().pagination.pageSize}`" />
</SelectTrigger> </SelectTrigger>
<SelectContent side="top"> <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 }} {{ pageSize }}
</SelectItem> </SelectItem>
</SelectContent> </SelectContent>

File diff suppressed because it is too large Load Diff