Skip to content

Commit 0fccaa3

Browse files
authored
Merge pull request #128 from 626-ju/refactor/wine-index
feat:index에 디바운스 추가+ 상세페이지 프리패칭
2 parents 71392e1 + 3c31f19 commit 0fccaa3

File tree

3 files changed

+86
-16
lines changed

3 files changed

+86
-16
lines changed

src/components/common/winelist/WineListCard.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { useRef } from 'react';
1+
import { useEffect, useRef } from 'react';
22

3+
import { useQueryClient } from '@tanstack/react-query';
34
import Link from 'next/link';
45

6+
import { getWineInfoForClient } from '@/api/getWineInfo';
57
import NextIcon from '@/assets/icons/Next.svg';
68
import StarIcon from '@/assets/icons/star.svg';
79
import { ImageCard } from '@/components/common/card/ImageCard';
@@ -25,21 +27,38 @@ export default function WineListCard() {
2527
threshold: 0.3,
2628
});
2729

28-
if (isLoading) return <p>불러오는 중...</p>;
29-
if (isError || !data) return <p>와인 데이터를 불러올 수 없습니다.</p>;
30-
31-
const wineList = data.pages.flatMap(
30+
const wineList = data?.pages.flatMap(
3231
(page) =>
3332
(page as GetWinesResponse)?.list?.filter((wine) => !wine.image.includes('example.com')) ?? [],
3433
);
3534

35+
const queryClient = useQueryClient();
36+
37+
const prefetchWineInfo = async (wineid: number) => {
38+
await queryClient.prefetchQuery({
39+
queryKey: ['wineDetail', wineid],
40+
queryFn: () => getWineInfoForClient(wineid),
41+
staleTime: 1000 * 60 * 5,
42+
});
43+
};
44+
45+
// // 데이터 프리패칭용
46+
useEffect(() => {
47+
wineList?.forEach((wine) => {
48+
prefetchWineInfo(wine.id);
49+
});
50+
}, [wineList]);
51+
52+
if (isLoading) return <p>불러오는 중...</p>;
53+
if (isError || !data) return <p>와인 데이터를 불러올 수 없습니다.</p>;
54+
3655
return (
3756
<div
3857
className='flex flex-col gap-[24px] px-[16px] mt-[12px] min-w-[370px] h-[390px]
3958
md:px-[20px] md:mt-[24px]
4059
xl:px-0 max-w-[1140px] mx-auto xl:max-w-[800px] xl:800px'
4160
>
42-
{wineList.map((wine) => (
61+
{wineList?.map((wine) => (
4362
<Link href={`/wines/${wine.id}`} key={wine.id} className='no-underline'>
4463
<div className='w-full bg-white border border-gray-300 rounded-xl flex flex-col relative min-w-[320px]'>
4564
<ImageCard

src/components/common/winelist/WineSlider.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import { useQuery } from '@tanstack/react-query';
1+
import { useEffect } from 'react';
22

3+
import { useQuery, useQueryClient } from '@tanstack/react-query';
4+
5+
import { getWineInfoForClient } from '@/api/getWineInfo';
36
import {
47
Carousel,
58
CarouselContent,
@@ -21,6 +24,22 @@ export default function WineSlider() {
2124
queryFn: () => getRecommendedWines({ teamId: TEAM_ID!, limit: RECOMMENDED_WINES_LIMIT }),
2225
});
2326

27+
const queryClient = useQueryClient();
28+
29+
const prefetchWineInfo = async (wineid: number) => {
30+
await queryClient.prefetchQuery({
31+
queryKey: ['wineDetail', wineid],
32+
queryFn: () => getWineInfoForClient(wineid),
33+
staleTime: 1000 * 60 * 5,
34+
});
35+
};
36+
37+
useEffect(() => {
38+
data?.forEach((wine) => {
39+
prefetchWineInfo(wine.id);
40+
});
41+
}, [data]);
42+
2443
return (
2544
<div className='mx-auto px-[16px] md:px-[20px] xl:px-0 max-w-[1140px] min-w-[365px] mt-[20px] mb-[24px]'>
2645
<section className='w-full min-h-[241px] rounded-[12px] bg-gray-100 py-[20px] md:min-h-[285px]'>

src/hooks/useWineListQuery.ts

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect, useRef, useState } from 'react';
2+
13
import { InfiniteData, useInfiniteQuery } from '@tanstack/react-query';
24

35
import { getWines } from '@/lib/wineApi';
@@ -8,30 +10,60 @@ import { GetWinesResponse } from '@/types/wineListType';
810
const PAGE_LIMIT = 8;
911
const TEAM_ID = process.env.NEXT_PUBLIC_TEAM;
1012

13+
function useDebounce<T>(value: T) {
14+
const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
15+
const [debouncedValue, setDebouncedValue] = useState<T>(() => value);
16+
17+
useEffect(() => {
18+
if (debounceTimer.current) clearTimeout(debounceTimer.current);
19+
debounceTimer.current = setTimeout(() => {
20+
setDebouncedValue(value);
21+
}, 1000);
22+
23+
return () => {
24+
if (debounceTimer.current) clearTimeout(debounceTimer.current);
25+
};
26+
}, [value]);
27+
return debouncedValue;
28+
}
29+
1130
export function useWineListQuery() {
1231
const type = useFilterStore((state) => state.type);
1332
const minPrice = useFilterStore((state) => state.minPrice);
1433
const maxPrice = useFilterStore((state) => state.maxPrice);
1534
const rating = useFilterStore((state) => state.rating);
1635
const searchTerm = useWineSearchKeywordStore((state) => state.searchTerm);
1736

37+
const debouncedType = useDebounce(type);
38+
const debouncedMinPrice = useDebounce(minPrice);
39+
const debouncedMaxPrice = useDebounce(maxPrice);
40+
const debouncedSearchTerm = useDebounce(searchTerm);
41+
1842
const apiRating = rating === 'all' ? undefined : Number(rating);
43+
const debouncedRating = useDebounce(apiRating);
1944

2045
return useInfiniteQuery<GetWinesResponse, unknown, InfiniteData<GetWinesResponse>>({
21-
queryKey: ['wines', { type, minPrice, maxPrice, rating: apiRating, name: searchTerm }],
46+
queryKey: [
47+
'wines',
48+
{
49+
type: debouncedType,
50+
minPrice: debouncedMinPrice,
51+
maxPrice: debouncedMaxPrice,
52+
rating: debouncedRating,
53+
name: debouncedSearchTerm,
54+
},
55+
],
2256
queryFn: ({ pageParam = 0 }) => {
2357
const filters = {
24-
type: type.toUpperCase(),
25-
minPrice,
26-
maxPrice,
27-
rating: apiRating,
28-
name: searchTerm,
58+
type: debouncedType.toUpperCase(),
59+
minPrice: debouncedMinPrice,
60+
maxPrice: debouncedMaxPrice,
61+
rating: debouncedRating,
62+
name: debouncedSearchTerm,
2963
};
3064

3165
const filteredParams = Object.fromEntries(
32-
Object.entries(filters).filter(
33-
([, value]) => value !== null && value !== undefined && value !== '',
34-
),
66+
Object.entries(filters).filter(([, value]) => value !== null && value !== undefined),
3567
);
3668

3769
return getWines({

0 commit comments

Comments
 (0)