useAudio/useVideo play lock resets across renders
What is the current behavior?
useAudio and useVideo use a lockPlay local variable inside createHTMLMediaHook to avoid calling pause() while a pending HTMLMediaElement.play() promise is still resolving.
Because lockPlay is a plain local variable, it is recreated on every render. Media events such as play, playing, waiting, pause, durationchange, or timeupdate can call setState, causing a rerender before the original play() promise settles. After that rerender, the lock is reset to false, so a new controls.pause() call can run while the earlier play() promise is still pending.
This weakens the Chromium workaround described in the comment above the lock:
Some browsers return
Promiseon.play()and may throw errors if one tries to execute another.play()or.pause()while that promise is resolving.
Expected behavior
The play lock should persist across renders until the pending play() promise resolves or rejects.
Using a ref for the lock would preserve the intended behavior without changing the public API.
Why this matters
In video/audio-heavy UIs, components often call controls.play() and controls.pause() in response to store changes, user interactions, or source changes. If a media event causes a rerender while play() is still pending, the current lock can be lost and the hook can issue a conflicting pause().
Possible fix
Change the local variable:
let lockPlay = false;to a ref-backed value, for example:
const lockPlay = useRef(false);and read/write lockPlay.current inside the controls.
I can open a PR with a focused regression test if this direction sounds good.
Source: streamich/react-use