diff --git a/src/hooks/useSmoothAnimation.ts b/src/hooks/useSmoothAnimation.ts index 296a6b7..e8790ca 100644 --- a/src/hooks/useSmoothAnimation.ts +++ b/src/hooks/useSmoothAnimation.ts @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useCallback } from 'react'; import { Position, TargetPosition } from '../types'; const SMOOTHING_THRESHOLD = 0.1; @@ -9,37 +9,45 @@ export function useSmoothAnimation( smoothFactor: number, setPosition: React.Dispatch> ) { - useEffect(() => { - if (position.x === null || position.y === null) return; - if (position.x === targetPosition.x && position.y === targetPosition.y) { - return; - } + // Memoize the smoothing calculation + const calculateNewPosition = useCallback( + (currentPosition: Position) => { + if (currentPosition.x === null || currentPosition.y === null) { + return currentPosition; + } - let animationFrameId: number; + const dx = targetPosition.x - currentPosition.x; + const dy = targetPosition.y - currentPosition.y; - if (smoothFactor === 1) { - setPosition(targetPosition); - return; - } + if ( + Math.abs(dx) < SMOOTHING_THRESHOLD && + Math.abs(dy) < SMOOTHING_THRESHOLD + ) { + return currentPosition; + } + + return { + x: currentPosition.x + dx / smoothFactor, + y: currentPosition.y + dy / smoothFactor, + }; + }, + [targetPosition.x, targetPosition.y, smoothFactor] + ); + + // Memoize the animation frame callback + const animate = useCallback(() => { + let animationFrameId: number; const smoothing = () => { setPosition((prev) => { - if (prev.x === null || prev.y === null) return prev; - - const dx = targetPosition.x - prev.x; - const dy = targetPosition.y - prev.y; + const newPosition = calculateNewPosition(prev); - if ( - Math.abs(dx) < SMOOTHING_THRESHOLD && - Math.abs(dy) < SMOOTHING_THRESHOLD - ) { + // Only trigger update if position actually changed + if (newPosition.x === prev.x && newPosition.y === prev.y) { return prev; } - return { - x: prev.x + dx / smoothFactor, - y: prev.y + dy / smoothFactor, - }; + return newPosition; }); animationFrameId = requestAnimationFrame(smoothing); @@ -52,7 +60,29 @@ export function useSmoothAnimation( cancelAnimationFrame(animationFrameId); } }; - }, [position.x, position.y, targetPosition, smoothFactor, setPosition]); + }, [calculateNewPosition, setPosition]); + + useEffect(() => { + // If smoothFactor is 1, just set position directly + if (smoothFactor === 1) { + setPosition(targetPosition); + return; + } + + // Skip animation if position is null + if (position.x === null || position.y === null) { + return; + } + + return animate(); + }, [ + smoothFactor, + position.x, + position.y, + targetPosition, + animate, + setPosition, + ]); return null; }