fix: improve infinite carousel navigation and transition handling

- Updated the track index logic to prevent navigation while at clone positions, ensuring smoother transitions.
- Enhanced the handleTransitionEnd function to only respond to the track's own transform transitions, improving event handling accuracy.
- Adjusted dependencies in useCallback hooks for better performance and reliability.
This commit is contained in:
barsa 2026-03-04 18:39:15 +09:00
parent a0f97cdec4
commit d5294dc580

View File

@ -48,10 +48,13 @@ export function useInfiniteCarousel<T>({ items }: { items: T[] }) {
const startAuto = useCallback(() => {
if (autoRef.current) clearInterval(autoRef.current);
autoRef.current = setInterval(() => {
setTrackIndex(prev => prev + 1);
setTrackIndex(prev => {
if (prev <= 0 || prev >= total + 1) return prev;
return prev + 1;
});
setIsTransitioning(true);
}, AUTO_INTERVAL);
}, []);
}, [total]);
const stopAuto = useCallback(() => {
if (autoRef.current) {
@ -65,15 +68,22 @@ export function useInfiniteCarousel<T>({ items }: { items: T[] }) {
return stopAuto;
}, [startAuto, stopAuto]);
const handleTransitionEnd = useCallback(() => {
if (trackIndex >= total + 1) {
setIsTransitioning(false);
setTrackIndex(1);
} else if (trackIndex <= 0) {
setIsTransitioning(false);
setTrackIndex(total);
}
}, [trackIndex, total]);
const handleTransitionEnd = useCallback(
(e: React.TransitionEvent) => {
// Only respond to the track's own transform transition,
// not bubbled events from child slide transitions (scale/opacity/filter)
if (e.target !== e.currentTarget || e.propertyName !== "transform") return;
if (trackIndex >= total + 1) {
setIsTransitioning(false);
setTrackIndex(1);
} else if (trackIndex <= 0) {
setIsTransitioning(false);
setTrackIndex(total);
}
},
[trackIndex, total]
);
useEffect(() => {
if (isTransitioning) return;
@ -83,11 +93,15 @@ export function useInfiniteCarousel<T>({ items }: { items: T[] }) {
const navigate = useCallback(
(updater: number | ((prev: number) => number)) => {
setTrackIndex(updater);
setTrackIndex(prev => {
// Block navigation while at a clone position (snap-back pending)
if (prev <= 0 || prev >= total + 1) return prev;
return typeof updater === "function" ? updater(prev) : updater;
});
setIsTransitioning(true);
startAuto();
},
[startAuto]
[startAuto, total]
);
const goTo = useCallback((i: number) => navigate(i + 1), [navigate]);