I'm trying to update a state variable with the value of the currentTime attribute from an element. I add an event listener to the 'timeupdate' event so I can call setPosition with the value of currentTime (position is used to position the knob on a slider representing song playback).
However, retrieving audioElement.currentTime and using the result as the argument to setPosition makes my browser (both Chrome and Safari) crash. In fact, the Activity Monitor on my macBook shows that the number of threads being used by the local website increases continuously as the audio file plays back, but I am not sure what that means. The site also uses significant memory, but ONLY when retrieving the currentTime attribute for every 'timeupdate' event.
I have no idea what is causing performance issues in my component, at least I'm assuming it is a performance issue.
The audio file played is .wav
function SongPlayer({ file }) {
const [audioElement] = useState(new Audio(file));
const [playing, setPlay] = useState(null);
const [audioContext] = useState(new AudioContext({ sampleRate: 44100 }));
const [gainNode] = useState(audioContext.createGain());
const [position, setPosition] = useState(0);
useEffect(
() => {
const track = audioContext.createMediaElementSource(audioElement);
track.connect(gainNode).connect(audioContext.destination);
audioElement.addEventListener('timeupdate', () => {
setPosition(audioElement.currentTime);
});
},
[],
);
useEffect(
() => {
if (playing) audioElement.play();
else if (!playing) audioElement.pause();
},
[playing],
);
return (
<>
</>
);
}
export default SongPlayer;
localhost using +500 threads and over 1Gb of memory
EDIT:
the problem was when I was calling new AudioContext() as an initial state value.
The constructor was getting called with every render.
This post helped me figure it out and explains it well: https://stackoverflow.com/a/64131447/13757284
I would recommend to you use Cleanup callback of useEffect, to remove eventListener.