Renta
Renta

Reputation: 75

Trouble unmounting component with Html5Qrcode

I'm using the Html5Qrcode package (https://github.com/mebjas/html5-qrcode) in my ReactJS app and it is 90% working great. I have read through the available documentation and see that, when I want to stop scanning, I should use:

html5QrCode.stop().then((ignore) => {
  // QR Code scanning is stopped.
}).catch((err) => {
  // Stop failed, handle it.
});

This works great when used after successfully decoding a QR code. The problem comes in when the user navigates away from the route without reading a code (navigating away from the page; "back", a different url, etc.). The camera keeps running in the background even without displaying the video feed.

I thought this should be handled with componentWillUnmount, but componentWillUnmount doesn't execute when navigating away from the page. I had tried the following:

componentWillUnmount() {
  const html5QrCode = Html5Qrcode("qr-reader")
  html5QrCode.stop.then(ignore => {
  }).catch(error =>
    console.log("Unable to unmount scanner", error))
}

but this results in an error:

Uncaught TypeError: Cannot set properties of undefined (setting 'element')

Here is the relevant code (largely copy pasted from documentation):

import React, { Component } from 'react';
import { Html5Qrcode } from 'html5-qrcode';


export default class Scanner extends Component {
  constructor(props) {
    super(props)

    this.state = {
      availableCameras: []
    }
  }

handleChange(event) {
  this.setState({
  [event.target.name] : event.target.value
  });
}
  
componentDidMount() {
  Html5Qrcode.getCameras().then(devices => {
    this.setState({
      availableCameras: devices
    })
    const html5QrCode = new Html5Qrcode("qr-reader");

  html5QrCode.start(
    { facingMode: "environment" },     // retrieved in the previous step.
    {
      fps: 2,    // sets the framerate to 10 frame per second
      qrbox: 250  // sets only 250 X 250 region of viewfinder to
                  // scannable, rest shaded.
    },
    qrCodeMessage => {
      // do something when code is read. For example:
      html5QrCode.stop().then(ignore => {
        // QR Code scanning is stopped.
      }).catch(err => {
        // Stop failed, handle it.
        console.log("Unable to stop scanning.", err);
      });
      this.props.returnedInfo(qrCodeMessage);
    },
    errorMessage => {
      // parse error, ideally ignore it. For example:
      console.log(`QR Code no longer in front of camera.`);
    })
  .catch(err => {
    // Start failed, handle it. For example,
    console.log(`Unable to start scanning, error: ${err}`);

  }).catch(error => {
    console.log("There was an error in Html5Qrcode component in componentDidMount", error)})
  })
}

componentWillUnmount() {
  const html5QrCode = Html5Qrcode("qr-reader")
  html5QrCode.stop.then(ignore => {
  }).catch(error =>
    console.log("Unable to unmount scanner", error))
}

  render () {
    return (
      <div id="qr-reader" />
    );
  }
}

In short: I need to unmount this component or somehow use the package's .stop method to turn off the users camera on manual navigation.

Upvotes: 3

Views: 1063

Answers (2)

shemaya
shemaya

Reputation: 196

I know this is old, but for anyone facing the same problem - I had the same problem and I got the solution from here

Basically when you render on the first useEffect use useTimeout in order to be sure you are not duplicating your component.

something like this:

// Timeout to allow the clean-up function to finish in case of double render.
setTimeout(() => {
  const container = document.getElementById(qrcodeRegionId);
  if (scannerRef.current && container?.innerHTML == "") {
    scannerRef.current.render(
      props.qrCodeSuccessCallback,
      props.qrCodeErrorCallback
    );
  }
}, 0);

Upvotes: 0

nreh
nreh

Reputation: 506

I don't know if this is a valid solution, but for me the issue disappeared after setting reactStrictMode to false.

See https://react.dev/reference/react/StrictMode if working on React

and https://nextjs.org/docs/app/api-reference/next-config-js/reactStrictMode if working with Next.JS

Although as most docs state, this is not recommended because reactStrictMode helps you make sure all components are properly unmounted and resources released.

Upvotes: 0

Related Questions