reactjsfunctionreact-routerunhandled

Function is executing even after leaving the page React js


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


Solution

  • 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).