Here is my component code (it is called on a page with <DetectPitch />
);
import { useEffect, useState } from 'react';
export default function DetectPitch() {
const [detect, setDetect] = useState(false);
useEffect(() => {
document.getElementById("mute-button").addEventListener("click", () => setDetect(detect => !detect))
}, []);
useEffect(() => {
function update(random) {
if (detect != false) {
console.log("updating", random)
window.setTimeout(() => update(random), 100);
}
}
const audioContext = new window.AudioContext();
if (detect) {
audioContext.resume()
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
update(Math.random());
});
} else {
audioContext.suspend()
}
}, [detect]);
return (
<button id="mute-button">{detect ? "Mute" : "Unmute"}</button>
)
}
This component renders a button
that when pressed toggles between mute/unmute based on the value of a react state, detect
. It also sets up listening to a users audio input device (I believe the audioContext
is being set multiple times but thats a seperate issue right now). I would like the browser to stop listening to the user audio input device when the button mute is pressed and stop logging "updating" to the console.
With the code as it currently is the audioContext
never stops and the message continues to log, this means that multiple presses of the button creates new timeouts that are looped infinitely at an increasing rate (this is demonstrated by the random number printed to the console, depending on how many times you have clicked the button the console displays multiple different random numbers).
I think this is happening because javascript is passing by value rather than reference and therefore the state never changes internally to the random()
function. I have tried using a getter function for detect
but that doesn't change anything and i've considered creating an object to hold the state but that makes the code more complex. I feel like there is a simpler options that i'm missing.
For now I would like to be able to get the timeout to stop printing so that I can continue debugging the functionality to use a single instance of audioContext.