Reputation: 75
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
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
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