I have created the following hook to play audio in react:
"use client";
import { useEffect, useState } from "react";
export const
useAudio = (url: string) => {
const = useState<HTMLAudioElement | null>(null);
const [playing, setPlaying] = useState(false);
const setVolume = (volume: number) => {
if (audio) audio.volume = volume;
console.log(audio);
};
const toggle = () => {
setPlaying(!playing);
console.log(audio);
};
useEffect(() => {
playing ? audio?.play() : audio?.pause();
}, [playing]);
useEffect(() => {
audio?.addEventListener("ended", () => audio?.play());
}, );
useEffect(() => {
setAudio(new Audio(url));
return () => {
audio?.removeEventListener("ended", () => audio.play());
};
}, []);
return { playing, toggle, setVolume };
};
When I console log the audio element inside the toggle function, I get the correct element, but in setVolume it is always null.
I set the volume in a eventListener mouseMove like this:
document.addEventListener("mousemove", function (e) {
let element = document.getElementById("follow");
let left = e.pageX;
let top = e.pageY;
element!.style.left = left + "px";
element!.style.top = top + "px";
const distance = Math.sqrt(
Math.pow(left - devPosition.current.x, 2) +
Math.pow(top - devPosition.current.y, 2)
);
setVolume(1 - distance / diagonal.current);
});
Can this happen because I call setVolume inside such a listener? If so, what can I do about that?
2
Answers
You’re setting
audio.volume
directly, but you’ll need to use thesetAudio
function, try something like this:Keep in mind that the
console.log
after thesetAudio
won’t show your change immediately:The useState set method is not reflecting a change immediately
I tried your
useAudio
hook and I think that there is nothing wrong with the hook.For example a component like this works as expected and doesn’t yield any error.
There could be issues in the way you handle the listener. If I understand correctly (for example look here How to add a 'mousemove' event listener to a component Cursor which is moved with the cursor pointer in ReactJS?) the preferred way to add a listener in a React component is by adding it to a DOM node, like this:
I don’t have access to the
devPosition
anddiagonal
variables that you use in your function, so I had to use a constant, but if you instantiate the listener in this way you are able to set the volume without issues.