1- import { useEffect } from 'react' ;
1+ import { useEffect , useState } from 'react' ;
22
33import { useQuery , useQueryClient } from '@tanstack/react-query' ;
44
99 CarouselItem ,
1010 CarouselPrevious ,
1111 CarouselNext ,
12+ type CarouselApi ,
1213} from '@/components/ui/carousel' ;
1314import { getRecommendedWines } from '@/lib/wineApi' ;
1415import { RecommendedWineResponse } from '@/types/wineListType' ;
@@ -40,6 +41,33 @@ export default function WineSlider() {
4041 } ) ;
4142 } , [ data ] ) ;
4243
44+ // useState 훅들을 여기에 선언합니다.
45+ const [ api , setApi ] = useState < CarouselApi | undefined > ( ) ;
46+ const [ isAtStart , setIsAtStart ] = useState ( true ) ;
47+ const [ isAtEnd , setIsAtEnd ] = useState ( false ) ;
48+
49+ // setApi prop에 직접 콜백을 작성하는 대신,
50+ // api 상태가 변경될 때마다 캐러셀 이벤트를 관리하는 useEffect 훅을 사용합니다.
51+ useEffect ( ( ) => {
52+ if ( ! api ) return ;
53+
54+ const handleSelect = ( ) => {
55+ setIsAtStart ( ! api . canScrollPrev ( ) ) ;
56+ setIsAtEnd ( ! api . canScrollNext ( ) ) ;
57+ } ;
58+
59+ // 초기 렌더링 시에도 상태를 업데이트합니다.
60+ handleSelect ( ) ;
61+
62+ api . on ( 'select' , handleSelect ) ;
63+ api . on ( 'reInit' , handleSelect ) ;
64+
65+ return ( ) => {
66+ api . off ( 'select' , handleSelect ) ;
67+ api . off ( 'reInit' , handleSelect ) ;
68+ } ;
69+ } , [ api ] ) ;
70+
4371 return (
4472 < div className = 'mx-auto px-[16px] md:px-[20px] xl:px-0 max-w-[1140px] min-w-[365px] mt-[20px] mb-[24px]' >
4573 < section className = 'w-full min-h-[241px] rounded-[12px] bg-gray-100 py-[20px] md:min-h-[285px]' >
@@ -65,21 +93,23 @@ export default function WineSlider() {
6593 align : 'start' ,
6694 slidesToScroll : 2 ,
6795 } }
96+ setApi = { setApi } // <-- useState로 선언한 setApi 함수를 prop으로 전달합니다.
6897 >
6998 < CarouselContent >
70- { filteredWines . map ( ( wine ) => (
99+ { filteredWines . map ( ( wine , index ) => (
71100 < CarouselItem key = { wine . id } className = 'basis-auto flex items-start ' >
72101 < WineCard
73102 id = { wine . id }
74103 image = { wine . image }
75104 name = { wine . name }
76105 rating = { wine . avgRating }
106+ isCarouselEnd = { isAtEnd && index >= filteredWines . length - 2 }
77107 />
78108 </ CarouselItem >
79109 ) ) }
80110 </ CarouselContent >
81- < CarouselPrevious />
82- < CarouselNext />
111+ < CarouselPrevious disabled = { isAtStart } className = 'z-50' />
112+ < CarouselNext disabled = { isAtEnd } className = 'z-50' />
83113 </ Carousel >
84114 ) ;
85115 } ) ( )
0 commit comments