useSynchronizedAnimation Deep Dive
The useSynchronizedAnimation hook is designed to keep multiple CSS animations with the same name in sync across different components. It ensures that when a new component with a specific animation mounts, its animation starts at the same relative time as already running animations of the same name.
Core Concept
In complex UI layouts, you might have multiple elements using the same CSS animation (e.g., a pulsing effect or a rotating spinner). If these elements mount at different times, their animations will be out of phase. useSynchronizedAnimation solves this by:
- Tracking Current Time: It stashes the current playback time of the animation.
- Phase Matching: When a new element mounts, it applies the stashed time to the new animation.
- Global Synchronization: It uses
document.getAnimations()to find all active animations and keep them aligned.
How it Works Step-by-Step
- Ref Creation: The hook creates a
useRefthat you must attach to the animated element. - Animation Discovery: It uses the Web Animations API (
document.getAnimations()) to find all animations matching the providedanimationName. - Target Matching: It identifies which specific animation from the list is attached to the component's
ref. - Synchronization Logic:
- If this is the first instance of this animation mounting, and there is a
stashedTime(from a previously unmounted instance), it resumes from that time. - If there are other instances already running, it syncs the current element's animation time to the time of the first discovered animation in the document.
- If this is the first instance of this animation mounting, and there is a
- Unmount Cleanup: When the component unmounts, if it was the "lead" animation (the first one in the list), it stashes its
currentTimeso that subsequent mounts can resume from that point.
Example
import { useSynchronizedAnimation } from '@archibald/storefront';
const PulsingComponent = ({ label }) => {
// This hook ensures that ALL 'pulse-effect' animations
// across the entire app stay perfectly in sync.
const syncRef = useSynchronizedAnimation("pulse-effect");
return (
<div className="pulse-container" ref={syncRef}>
<span>{label}</span>
</div>
);
};
Note: This hook relies on the Web Animations API. If the browser does not support document.getAnimations, the hook will gracefully degrade and the animations will run independently.