fix(card-sorting): use empty deps array for useSprings to prevent recreation

Added empty dependency array to useSprings and track animation state
with ref to ensure springs are only created once and never reset.

Changes:
- Add empty deps array to useSprings (prevents recreation)
- Track animation completion with hasAnimatedRef
- If already animated, start new springs at grid positions
- Only run animation effect once

This ensures cards stay in grid positions through all re-renders.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-10-23 23:05:30 -05:00
parent 66cea3e43f
commit cee399ed15
1 changed files with 30 additions and 9 deletions

View File

@ -106,21 +106,41 @@ export function ResultsPhase() {
}
}
// Create springs for each card - use useMemo to prevent recreation on every render
// Create springs for each card - memoize to prevent recreation
const initialPositions = useMemo(() => {
return userSequence.map((card) => getInitialPosition(card.id))
}, []) // Empty deps - only calculate once on mount
const [springs, api] = useSprings(userSequence.length, (index) => {
return {
from: initialPositions[index],
to: initialPositions[index],
config: config.gentle,
}
})
// Track if animation has completed
const hasAnimatedRef = useRef(false)
const [springs, api] = useSprings(
userSequence.length,
(index) => {
// If already animated, start at grid position
if (hasAnimatedRef.current) {
const card = userSequence[index]
const correctIndex = state.correctOrder.findIndex((c) => c.id === card.id)
return {
from: calculateGridPosition(correctIndex),
to: calculateGridPosition(correctIndex),
config: config.gentle,
}
}
// Otherwise start at initial position
return {
from: initialPositions[index],
to: initialPositions[index],
config: config.gentle,
}
},
[] // Empty deps - only create once
)
// Immediately start animating to grid positions
useEffect(() => {
if (hasAnimatedRef.current) return // Don't animate again
// Small delay to ensure mount
const timer = setTimeout(() => {
api.start((index) => {
@ -131,9 +151,10 @@ export function ResultsPhase() {
config: { ...config.gentle, tension: 120, friction: 26 },
}
})
hasAnimatedRef.current = true
}, 100)
return () => clearTimeout(timer)
}, [api, userSequence, state.correctOrder])
}, [])
// Show corrections after animation completes
useEffect(() => {