VirtualList
Rendu efficace de grandes listes en affichant uniquement les éléments visibles. Propulsé par @tanstack/react-virtual.
Installation
Section intitulée « Installation »Ce composant nécessite @tanstack/react-virtual comme dépendance pair :
npm install @tanstack/react-virtualImportation
Section intitulée « Importation »import { VirtualList } from 'asterui/virtuallist'Exemples
Section intitulée « Exemples »Utilisation basique
Rendu efficace d'une liste de 10 000 éléments.
import { VirtualList } from 'asterui/virtuallist'
function App() {
const basicItems = Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `Item ${i + 1}`
}))
return (
<VirtualList
items={basicItems}
height={300}
itemHeight={40}
className="border border-base-300 rounded-lg"
renderItem={(item) => (
<div className="p-2 border-b border-base-300 flex items-center h-full">
{item.name}
</div>
)}
/>
)
}
export default App Liste stylisée
Avec style de carte et effets de survol.
import { VirtualList } from 'asterui/virtuallist'
function App() {
const users = Array.from({ length: 5000 }, (_, i) => ({
id: i,
name: `User ${i + 1}`,
email: `user${i + 1}@example.com`
}))
return (
<VirtualList
items={users}
height={300}
itemHeight={60}
className="border border-base-300 rounded-lg"
renderItem={(user) => (
<div className="p-3 hover:bg-base-200 transition-colors border-b border-base-300 h-full flex flex-col justify-center">
<div className="font-medium">{user.name}</div>
<div className="text-sm text-base-content/60">{user.email}</div>
</div>
)}
/>
)
}
export default App Avec espacement
Éléments espacés avec un intervalle entre eux.
import { VirtualList } from 'asterui/virtuallist'
function App() {
const cardItems = Array.from({ length: 1000 }, (_, i) => ({
id: i,
title: `Card ${i + 1}`,
description: 'A brief description'
}))
return (
<VirtualList
items={cardItems}
height={300}
itemHeight={72}
gap={8}
className="p-2 border border-base-300 rounded-lg"
renderItem={(item) => (
<div className="card bg-base-200 p-3 h-full flex flex-col justify-center">
<h3 className="font-bold">{item.title}</h3>
<p className="text-sm text-base-content/70">{item.description}</p>
</div>
)}
/>
)
}
export default App Callback de défilement
Suivre la position de défilement pour le chargement infini ou l'analyse.
Scroll position: 0px
import { VirtualList } from 'asterui/virtuallist'
import { useState } from 'react'
function App() {
const scrollItems = Array.from({ length: 10000 }, (_, i) => ({ id: i }))
const [scrollTop, setScrollTop] = useState(0)
return (
<div>
<div className="mb-2 text-sm text-base-content/70">Scroll position: {Math.round(scrollTop)}px</div>
<VirtualList
items={scrollItems}
height={250}
itemHeight={40}
onScroll={setScrollTop}
className="border border-base-300 rounded-lg"
renderItem={(_, index) => (
<div className="p-2 border-b border-base-300 flex items-center h-full">
Row {index + 1}
</div>
)}
/>
</div>
)
}
export default App Hauteur variable (Chat)
Messages de chat de différentes longueurs utilisant le composant Chat.
import { Chat } from 'asterui'
import { VirtualList } from 'asterui/virtuallist'
function App() {
const chatMessages = [
{ id: 1, user: 'Alex', text: 'Hey!' },
{ id: 2, user: 'You', text: 'Hi Alex, what\'s up?' },
{ id: 3, user: 'Alex', text: 'Not much, just wanted to check if you\'re coming to the party on Saturday' },
{ id: 4, user: 'You', text: 'Oh yeah, I\'ll be there! What time does it start?' },
{ id: 5, user: 'Alex', text: '8pm' },
{ id: 6, user: 'You', text: 'Cool' },
{ id: 7, user: 'Alex', text: 'Can you bring some snacks? We\'re running low on chips and stuff. Maybe grab a couple bags of tortilla chips and some salsa if you can find good ones' },
{ id: 8, user: 'You', text: 'Sure thing, I\'ll stop by the store on the way' },
{ id: 9, user: 'Alex', text: 'Thanks!' },
{ id: 10, user: 'You', text: 'No problem. Who else is coming?' },
{ id: 11, user: 'Alex', text: 'Sarah, Mike, probably Jordan. Maybe a few others' },
{ id: 12, user: 'You', text: 'Nice' },
{ id: 13, user: 'Alex', text: 'Yeah it should be fun. We\'re gonna set up the projector in the backyard for a movie later if the weather holds up' },
{ id: 14, user: 'You', text: 'What movie?' },
{ id: 15, user: 'Alex', text: 'Haven\'t decided yet. Any suggestions?' },
{ id: 16, user: 'You', text: 'How about something funny? We could do a comedy' },
{ id: 17, user: 'Alex', text: 'Good idea' },
{ id: 18, user: 'You', text: 'Alright, see you Saturday then!' },
{ id: 19, user: 'Alex', text: 'See ya!' },
{ id: 20, user: 'You', text: '👋' },
]
return (
<VirtualList
items={chatMessages}
height={300}
itemHeight={(msg) => 70 + Math.floor(msg.text.length / 40) * 24}
className="bg-base-100 border border-base-300 rounded-lg p-2"
renderItem={(msg) => (
<Chat
position={msg.user === 'You' ? 'end' : 'start'}
header={msg.user}
message={msg.text}
color={msg.user === 'You' ? 'primary' : undefined}
/>
)}
/>
)
}
export default App VirtualList
Section intitulée « VirtualList »| Propriété | Description | Type | Défaut |
|---|---|---|---|
items | Tableau d’éléments à rendre | T[] | - |
height | Hauteur du conteneur défilable | number | string | - |
itemHeight | Hauteur fixe, ou fonction retournant la hauteur estimée par élément pour les hauteurs variables | number | ((item: T, index: number) => number) | - |
renderItem | Fonction de rendu pour chaque élément | (item: T, index: number) => ReactNode | - |
overscan | Nombre d’éléments à rendre en dehors de la zone visible | number | 5 |
gap | Espacement entre les éléments en pixels | number | 0 |
width | Largeur du conteneur | number | string | - |
className | Classe supplémentaire pour le conteneur de défilement | string | - |
innerClassName | Classe supplémentaire pour le conteneur interne | string | - |
itemClassName | Classe supplémentaire pour chaque wrapper d’élément | string | - |
onScroll | Callback lorsque la position de défilement change | (scrollTop: number) => void | - |
data-testid | ID de test pour les tests | string | - |
Conseils de performance
Section intitulée « Conseils de performance »- Utilisez une
itemHeightfixe lorsque c’est possible pour de meilleures performances - Mémorisez votre fonction
renderItemsi elle est coûteuse - Augmentez
overscansi vous constatez un scintillement lors d’un défilement rapide - Gardez les composants d’éléments simples - évitez les calculs lourds dans le rendu