Skip to content

Commit 7ca8296

Browse files
committed
feat: virtualize realtime event stream for high-scale performance
1 parent c3084e4 commit 7ca8296

1 file changed

Lines changed: 65 additions & 11 deletions

File tree

web/src/components/events/event-stream.tsx

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ import type { Event } from "@/types/event"
5858

5959
import { EventRow } from "./event-row"
6060

61+
import {
62+
useRef,
63+
} from "react"
64+
65+
import {
66+
useVirtualizer,
67+
} from "@tanstack/react-virtual"
68+
6169
type Props = {
6270
events: Event[]
6371
selectedEvent: Event | null
@@ -68,7 +76,22 @@ export function EventStream({
6876
events,
6977
selectedEvent,
7078
onSelect,
71-
}: Props) {
79+
}: Props)
80+
{
81+
const parentRef =
82+
useRef<HTMLDivElement>(null)
83+
84+
const virtualizer =
85+
useVirtualizer({
86+
count: events.length,
87+
getScrollElement: () =>
88+
parentRef.current,
89+
estimateSize: () => 72,
90+
overscan: 8,
91+
})
92+
93+
const items =
94+
virtualizer.getVirtualItems()
7295
return (
7396
<div className="flex h-full flex-col overflow-hidden">
7497

@@ -90,26 +113,52 @@ export function EventStream({
90113
)}
91114

92115
{/* Rows */}
93-
<div className="flex-1 overflow-y-auto">
116+
<div
117+
ref={parentRef}
118+
className="flex-1 overflow-y-auto"
119+
>
120+
121+
<div
122+
style={{
123+
height:
124+
virtualizer.getTotalSize(),
125+
position: "relative",
126+
}}
127+
>
128+
129+
{items.map(
130+
(virtualRow) => {
131+
const event =
132+
events[
133+
virtualRow.index
134+
]
135+
136+
if (!event)
137+
return null
138+
139+
return (
140+
<div
141+
key={event.id}
142+
className="absolute left-0 top-0 w-full"
143+
style={{
144+
transform: `translateY(${virtualRow.start}px)`,
145+
}}
146+
>
94147

95-
{events.map(
96-
(event, index) => (
97148
<motion.div
98-
key={event.id}
99149
initial={{
100150
opacity: 0,
101-
y: -8,
151+
y: -6,
102152
}}
103153
animate={{
104154
opacity: 1,
105155
y: 0,
106156
}}
107157
transition={{
108158
duration: 0.18,
109-
delay:
110-
index * 0.015,
111159
}}
112160
>
161+
113162
<EventRow
114163
event={event}
115164
selected={
@@ -120,10 +169,15 @@ export function EventStream({
120169
onSelect(event)
121170
}
122171
/>
172+
123173
</motion.div>
124-
)
125-
)}
126-
</div>
174+
175+
</div>
176+
)
177+
}
178+
)}
179+
</div>
180+
</div>
127181
</div>
128182
)
129183
}

0 commit comments

Comments
 (0)