|
1 | 1 | 'use client'; |
2 | 2 | import { useState, useEffect, useMemo } from 'react'; |
3 | | -import { useSuspenseQuery } from '@tanstack/react-query'; |
| 3 | +import { useSuspenseQuery, useQueryClient } from '@tanstack/react-query'; |
4 | 4 | import { getActivityDetail } from '@/app/api/activities'; |
| 5 | +import type { ActivityDetail } from '@/types/activities.type'; |
5 | 6 | import { useRecentViewedStore } from '@/store/recentlyWatched'; |
6 | 7 | import ActivityImageViewer from '@/components/pages/activities/ActivityImageViewer'; |
7 | 8 | import ActivityInfo from '@/components/pages/activities/ActivityInfo'; |
@@ -29,6 +30,7 @@ interface ActivityClientProps { |
29 | 30 | export default function ActivityClient({ activityId, blurImage }: ActivityClientProps) { |
30 | 31 | const [isOwner, setIsOwner] = useState<boolean>(false); |
31 | 32 | const { user } = useUserStore(); |
| 33 | + const queryClient = useQueryClient(); |
32 | 34 |
|
33 | 35 | // Intersection Observer for performance optimization |
34 | 36 | const [mapRef, isMapVisible] = useIntersectionObserver({ |
@@ -56,11 +58,31 @@ export default function ActivityClient({ activityId, blurImage }: ActivityClient |
56 | 58 | gcTime: 60 * 60 * 1000, // 1시간 메모리 보관 |
57 | 59 | }); |
58 | 60 |
|
59 | | - // 2. 동적 데이터 (가격, 스케줄, 평점) - 짧은 캐시 |
| 61 | + // 2. 동적 데이터 (가격, 스케줄, 평점) - 짧은 캐시, 캐시 재사용 최적화 |
60 | 62 | const { data: dynamicInfo } = useSuspenseQuery({ |
61 | 63 | queryKey: [...activityQueryKeys.detail(activityId), 'dynamic'], |
62 | | - queryFn: () => getActivityDetail(Number(activityId)), |
63 | | - select: (data) => ({ |
| 64 | + queryFn: (): Promise<ActivityDetail> => { |
| 65 | + // 캐시된 데이터가 있으면 재사용, 없으면 새로 호출 |
| 66 | + const cachedData = queryClient.getQueryData<ActivityDetail>([ |
| 67 | + ...activityQueryKeys.detail(activityId), |
| 68 | + 'static', |
| 69 | + ]); |
| 70 | + const cachedState = queryClient.getQueryState([ |
| 71 | + ...activityQueryKeys.detail(activityId), |
| 72 | + 'static', |
| 73 | + ]); |
| 74 | + |
| 75 | + // static 캐시가 fresh하면(2분 이내) 재사용 |
| 76 | + if ( |
| 77 | + cachedData && |
| 78 | + cachedState?.dataUpdatedAt && |
| 79 | + Date.now() - cachedState.dataUpdatedAt < 2 * 60 * 1000 |
| 80 | + ) { |
| 81 | + return Promise.resolve(cachedData); // 캐시 재사용 |
| 82 | + } |
| 83 | + return getActivityDetail(Number(activityId)); // 새 호출 |
| 84 | + }, |
| 85 | + select: (data: ActivityDetail) => ({ |
64 | 86 | price: data.price, |
65 | 87 | schedules: data.schedules, |
66 | 88 | rating: data.rating, |
|
0 commit comments