improved audio effect fix
This commit is contained in:
parent
58ebeea23b
commit
33a4abe45f
@ -83,9 +83,9 @@ export function useAudioEffects({
|
||||
const wasHoveredRef = useRef(false);
|
||||
const wasActiveRef = useRef(false);
|
||||
|
||||
// Track if initial state sync is complete (skip audio on first render)
|
||||
// User can't hover during mount, so any true state is stale
|
||||
const didInitRef = useRef(false);
|
||||
// Delay audio playback after mount/reset to avoid browser autoplay policy
|
||||
// User can't hover during mount, so any true state within 100ms is stale
|
||||
const [canPlay, setCanPlay] = useState(false);
|
||||
|
||||
// Track which URLs we've already fetched to prevent duplicate fetches
|
||||
const lastFetchedHoverUrlRef = useRef<string | null>(null);
|
||||
@ -99,6 +99,18 @@ export function useAudioEffects({
|
||||
const [hoverAudioReady, setHoverAudioReady] = useState(false);
|
||||
const [clickAudioReady, setClickAudioReady] = useState(false);
|
||||
|
||||
// Enable audio playback after short delay to skip stale state at mount
|
||||
// Any hover/active state within 100ms of mount is not from real user interaction
|
||||
useEffect(() => {
|
||||
setCanPlay(false);
|
||||
wasHoveredRef.current = isHovered;
|
||||
wasActiveRef.current = isActive;
|
||||
const timer = setTimeout(() => setCanPlay(true), 100);
|
||||
return () => clearTimeout(timer);
|
||||
// Only reset on resetKey change, not on isHovered/isActive changes
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [resetKey]);
|
||||
|
||||
// Initialize hover audio element - fetch with credentials for auth
|
||||
useEffect(() => {
|
||||
if (!hoverAudioUrl) {
|
||||
@ -242,15 +254,9 @@ export function useAudioEffects({
|
||||
|
||||
// Play hover audio when hover starts (plays to completion, not interrupted)
|
||||
useEffect(() => {
|
||||
// Skip audio on initial render - sync state only
|
||||
// User can't hover during mount, so any true state is stale
|
||||
if (!didInitRef.current) {
|
||||
didInitRef.current = true;
|
||||
wasHoveredRef.current = isHovered;
|
||||
return;
|
||||
}
|
||||
|
||||
// Only play if: canPlay is true, hover changed from false→true, audio is ready
|
||||
if (
|
||||
canPlay &&
|
||||
isHovered &&
|
||||
!wasHoveredRef.current &&
|
||||
hoverAudioRef.current &&
|
||||
@ -265,18 +271,13 @@ export function useAudioEffects({
|
||||
});
|
||||
}
|
||||
wasHoveredRef.current = isHovered;
|
||||
}, [isHovered, hoverAudioReady]);
|
||||
}, [canPlay, isHovered, hoverAudioReady]);
|
||||
|
||||
// Play click audio when active state begins
|
||||
useEffect(() => {
|
||||
// Skip audio on initial render - sync state only
|
||||
// Note: didInitRef is already set by hover effect due to effect ordering
|
||||
if (!didInitRef.current) {
|
||||
wasActiveRef.current = isActive;
|
||||
return;
|
||||
}
|
||||
|
||||
// Only play if: canPlay is true, active changed from false→true, audio is ready
|
||||
if (
|
||||
canPlay &&
|
||||
isActive &&
|
||||
!wasActiveRef.current &&
|
||||
clickAudioRef.current &&
|
||||
@ -289,7 +290,7 @@ export function useAudioEffects({
|
||||
});
|
||||
}
|
||||
wasActiveRef.current = isActive;
|
||||
}, [isActive, clickAudioReady]);
|
||||
}, [canPlay, isActive, clickAudioReady]);
|
||||
|
||||
// Manual click audio trigger
|
||||
const playClickAudio = useCallback(() => {
|
||||
@ -312,12 +313,10 @@ export function useAudioEffects({
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Reset audio on key change (e.g., page navigation or element change)
|
||||
// Stop audio on key change (e.g., page navigation or element change)
|
||||
// Note: canPlay and refs are reset in the canPlay effect above
|
||||
useEffect(() => {
|
||||
stopAll();
|
||||
wasHoveredRef.current = false;
|
||||
wasActiveRef.current = false;
|
||||
didInitRef.current = false; // Reset for new element
|
||||
}, [resetKey, stopAll]);
|
||||
|
||||
return { playClickAudio, stopAll };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user