Skip to content

Commit 04c2f63

Browse files
committed
refact: virtuosoGrid로 수정
1 parent 911db6c commit 04c2f63

File tree

1 file changed

+39
-111
lines changed

1 file changed

+39
-111
lines changed

src/features/event/ui/EventList.tsx

Lines changed: 39 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { useRef, useEffect, useState } from 'react';
1+
import { VirtuosoGrid } from 'react-virtuoso';
2+
import { useNavigate } from 'react-router-dom';
23
import { useInfiniteScroll } from '../../../shared/hooks/useInfiniteScroll';
3-
import { getAllEventsInfinite, getCategoryEventsInfinite } from '../../../entities/event/api/event';
44
import EventCard from '../../../shared/ui/EventCard';
55
import { BaseEvent, CategoryType, TagType } from '../../../shared/types/baseEventType';
6-
import { useNavigate } from 'react-router-dom';
7-
import { useVirtualizer } from '@tanstack/react-virtual';
8-
6+
import { getAllEventsInfinite, getCategoryEventsInfinite } from '../../../entities/event/api/event';
97
interface EventListProps extends BaseEvent {
108
id: number;
119
hostChannelName: string;
@@ -27,10 +25,6 @@ const categoryToKorean: Record<CategoryType, string> = {
2725
const EventList = ({ category, tag }: EventListComponentProps) => {
2826
const navigate = useNavigate();
2927

30-
const MOBILE_CARD_HEIGHT = 250;
31-
const DESKTOP_CARD_HEIGHT = 330;
32-
33-
3428
const { data, fetchNextPage, hasNextPage, isFetching } = useInfiniteScroll<EventListProps>({
3529
queryKey: ['events', 'infinite', category ?? '', tag ?? ''],
3630
queryFn: params => {
@@ -44,113 +38,47 @@ const EventList = ({ category, tag }: EventListComponentProps) => {
4438
});
4539

4640
const flatEvents = data?.pages.flatMap(page => page.items) ?? [];
47-
const parentRef = useRef<HTMLDivElement>(null);
48-
const firstRowRef = useRef<HTMLDivElement>(null);
49-
50-
// 반응형
51-
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
52-
useEffect(() => {
53-
const handleResize = () => setWindowWidth(window.innerWidth);
54-
window.addEventListener('resize', handleResize);
55-
return () => window.removeEventListener('resize', handleResize);
56-
}, []);
57-
const isMobile = windowWidth < 768;
5841

59-
const [rowHeight, setRowHeight] = useState(isMobile ? MOBILE_CARD_HEIGHT : DESKTOP_CARD_HEIGHT);
60-
61-
useEffect(() => {
62-
if (!firstRowRef.current) return;
63-
requestAnimationFrame(() => {
64-
const measuredHeight = firstRowRef.current!.offsetHeight;
65-
if (measuredHeight && measuredHeight !== rowHeight) {
66-
setRowHeight(measuredHeight);
67-
}
68-
});
69-
}, [flatEvents, windowWidth]);
70-
71-
const rowCount = Math.ceil(flatEvents.length / 2);
72-
const rowVirtualizer = useVirtualizer({
73-
count: rowCount,
74-
getScrollElement: () => parentRef.current,
75-
estimateSize: () => isMobile ? MOBILE_CARD_HEIGHT : DESKTOP_CARD_HEIGHT,
76-
measureElement: el => el.getBoundingClientRect().height,
77-
overscan: 5,
78-
});
79-
80-
useEffect(() => {
81-
const virtualItems = rowVirtualizer.getVirtualItems();
82-
if (virtualItems.length === 0) return;
83-
84-
const lastVirtualItem = virtualItems[virtualItems.length - 1];
85-
if (lastVirtualItem.index >= rowCount - 1 && hasNextPage && !isFetching) {
86-
fetchNextPage();
87-
}
88-
}, [rowVirtualizer.getVirtualItems(), rowCount, hasNextPage, isFetching, fetchNextPage]);
42+
if (flatEvents.length === 0) {
43+
return (
44+
<div className="sm:text-12 md:text-14 lg:text-16 py-8 text-placeholderText ">
45+
{tag ? (
46+
<div>열린 이벤트가 없습니다.</div>
47+
) : category ? (
48+
<div>열린 {categoryToKorean[category]} 이벤트가 없습니다.</div>
49+
) : null}
50+
</div>
51+
);
52+
}
8953

9054
return (
9155
<>
92-
{flatEvents.length === 0 ? (
93-
<div className="sm:text-12 md:text-14 lg:text-16 py-8 text-placeholderText ">
94-
{tag ? (
95-
<div>열린 이벤트가 없습니다.</div>
96-
) : category ? (
97-
<div>열린 {categoryToKorean[category]} 이벤트가 없습니다.</div>
98-
) : null}
99-
</div>
100-
) : (
101-
<div
102-
ref={parentRef}
103-
className="relative w-[90%] mx-auto h-[80vh] md:h-[85vh] lg:h-[90vh] overflow-auto pb-20"
104-
role="region"
105-
aria-label="이벤트 목록"
106-
tabIndex={0}
107-
>
108-
<div
109-
style={{ height: `${rowVirtualizer.getTotalSize()}px`, position: 'relative' }}
110-
className="relative"
111-
>
112-
{rowVirtualizer.getVirtualItems().map(virtualRow => {
113-
const firstIndex = virtualRow.index * 2;
114-
const secondIndex = firstIndex + 1;
115-
116-
const items = [flatEvents[firstIndex], flatEvents[secondIndex]].filter(Boolean);
56+
<VirtuosoGrid
57+
style={{ height: '80vh', width: '90%', margin: '0 auto' }} // 높이 명시 필수!
58+
useWindowScroll={true} // 전체 창 스크롤 아니라면 false 권장
59+
data={flatEvents}
60+
endReached={() => {
61+
if (hasNextPage && !isFetching) fetchNextPage();
62+
}}
63+
overscan={200}
64+
listClassName="flex flex-wrap justify-between"
65+
itemClassName="w-[48%] mb-4 cursor-pointer"
66+
itemContent={(_index, event) => (
67+
<EventCard
68+
key={event.id}
69+
id={event.id}
70+
img={event.bannerImageUrl}
71+
eventTitle={event.title}
72+
eventDate={event.startDate}
73+
location={event.address}
74+
host={event.hostChannelName}
75+
hashtags={event.hashtags}
76+
dDay={event.remainDays}
77+
onClick={() => navigate(`/event-details/${event.id}`)}
78+
/>
79+
)}
80+
/>
11781

118-
return (
119-
<div
120-
key={virtualRow.index}
121-
ref={virtualRow.index === 0 ? firstRowRef : null}
122-
style={{
123-
position: 'absolute',
124-
top: 0,
125-
left: 0,
126-
width: '100%',
127-
transform: `translateY(${virtualRow.start}px)`,
128-
}}
129-
className="grid grid-cols-2 gap-4"
130-
>
131-
{items.map(event => (
132-
<div
133-
key={event.id}
134-
onClick={() => navigate(`/event-details/${event.id}`)}
135-
>
136-
<EventCard
137-
id={event.id}
138-
img={event.bannerImageUrl}
139-
eventTitle={event.title}
140-
eventDate={event.startDate}
141-
location={event.address}
142-
host={event.hostChannelName}
143-
hashtags={event.hashtags}
144-
dDay={event.remainDays}
145-
/>
146-
</div>
147-
))}
148-
</div>
149-
);
150-
})}
151-
</div>
152-
</div>
153-
)}
15482
{isFetching && <div className="text-center py-4">Loading...</div>}
15583
</>
15684
);

0 commit comments

Comments
 (0)