When I navigate from home i.e, "/" to "/realtime" useEffect hook start the video from webcam, then I added a function handleVideoPlay for video onPlay event as shown below.
<video
className="video"
ref={videoRef}
autoPlay
muted
onPlay={handleVideoPlay}
/>
For every interval of 100ms, the code inside setInterval( which is inside the handleVideoPlay function) will run, which detects facial emotions using faceapi and draw canvas.
Here is my handleVideoPlay function
const [ isOnPage, setIsOnPage] = useState(true);
const handleVideoPlay = () => {
setInterval(async () => {
if(isOnPage){
canvasRef.current.innerHTML = faceapi.createCanvasFromMedia(videoRef.current);
const displaySize = {
width: videoWidth,
height: videoHeight,
};
faceapi.matchDimensions(canvasRef.current, displaySize);
const detections = await faceapi.detectAllFaces(videoRef.current, new
faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceExpressions();
const resizeDetections = faceapi.resizeResults(detections, displaySize);
canvasRef.current.getContext("2d").clearRect(0, 0, videoWidth, videoHeight);
faceapi.draw.drawDetections(canvasRef.current, resizeDetections);
faceapi.draw.drawFaceLandmarks(canvasRef.current, resizeDetections);
faceapi.draw.drawFaceExpressions(canvasRef.current, resizeDetections);
}else{
return;
}
}, 100);
};
The problem is when I go back the handleVideoFunction is still running, so for canvasRef it is getting null value, and it's throwing this error as shown below
Unhandled Rejection (TypeError): Cannot read property 'getContext' of null
I want to stop the setInterval block on leaving the page. I tried by putting a state isOnPage to true and I set it to false in useEffect cleanup so that if isOnPage is true the code in setInterval runs else it returns. but that doesn't worked. The other code in useEffect cleanup function is running but the state is not changing. Please help me with this, and I'm sorry if haven't asked the question correctly and I'll give you if you need more information about this to resolve. Thank you
You need to clear your setInterval
from running when the component is unmounted.
You can do this using the useEffect
hook:
useEffect(() => {
const interval = setInterval(() => {
console.log('I will log every second until I am cleared');
}, 1000);
return () => clearInterval(interval);
}, []);
Passing an empty array to useEffect
ensures the effect will only trigger once when it is mounted.
The return
of the effect is called when the component is unmounted.
If you clear the interval here, you will no longer have the interval running once the component is unmounted. Not only that, but you are ensuring that you are not leaking memory (i.e. by indefinitely increasing the number of setIntervals
that are running in the background).