Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two cameras appear on reload of page (implementing the scanner as a react component) #641

Open
ThorbjoernJensen opened this issue Dec 6, 2022 · 7 comments

Comments

@ThorbjoernJensen
Copy link

Description
a double camera appears when using the scanner as a react component.
On first load of site, after grating rights to the camera, it only shows one camera, as intended,
On every following load two cameras appear (see attachment)
Clearing the cache makes the problem disappear. but the camera double reappears on new reload.

Windows 11
happens in Chrome, Firefox and Edge
React 18.2.0 using Vite 3.2.3
double camera

@ThorbjoernJensen
Copy link
Author

Maybe this should have been posted in the react repository.
I found a solutionen. I had to do with the vite build. In the index.js file it used a different render method from react-dom-client, that didnt work with well with the rest of the codebase.

@cinc-b
Copy link

cinc-b commented Dec 6, 2022

Do you maybe know a way to fix that in React too?
If not could u tell me how u exactly fixed it with vite.js?

React 18.2.0
Windows 10
Browser: Firefox, Chrome, Edge

This would be the code snippet if it helps.

const BarcodeScannerPluginRework = () => {
  useEffect(() => {
    // Anything in here is fired on component mount.
    const html5QrCode = new Html5Qrcode(qrcodeId);
    const qrCodeSuccessCallback = (decodedText, decodedResult) => {
      /* handle success */
    };
    const config = { fps: 10, qrbox: { width: 250, height: 250 }, aspectRatio: 1.777778};

    // If you want to prefer back camera
    html5QrCode.start(
      { facingMode: "environment" },
      config,
      qrCodeSuccessCallback
    );
    return () => {
      // Anything in here is fired on component unmount.

    };
  }, []);

  return <div id={qrcodeId}></div>;
};

@RobinSCU
Copy link

RobinSCU commented Dec 6, 2022

@cinc-b
I had the same problem a minute ago and the problem I saw is that with a code like this the scanner gets initialized at least two times.

To fix it I just moved the const html5QrCode out of the useEffect to hold a global reference.

something like that:

const BarcodeScannerPluginRework = () => {
    let html5QrCode;
    
    useEffect(() => {
        // Anything in here is fired on component mount.
        if(!html5QrCode?.getState()){
            html5QrCode = new Html5Qrcode(qrcodeId);
            const qrCodeSuccessCallback = (decodedText, decodedResult) => {
                /* handle success */
            };
            const config = { fps: 10, qrbox: { width: 250, height: 250 }, aspectRatio: 1.777778};

            // If you want to prefer back camera
            html5QrCode.start(
                { facingMode: "environment" },
                config,
                qrCodeSuccessCallback
            );
        }

        return () => {
            // Anything in here is fired on component unmount.

        };
    }, []);

    return <div id={qrcodeId}></div>;
};

currently, it works for me

@cinc-b
Copy link

cinc-b commented Dec 7, 2022

@RobinSCU Ty for ur help. It works now. Could you tell me why it doesnt work if I remove the
if(!html5QrCode?.getState()) statement?

@RobinSCU
Copy link

RobinSCU commented Dec 7, 2022

i would say it's because the html5QrCode element gets injected twice in the DOM and with the getState() function we check if the qrCode is already initialized.

Here is a bit of a different approach #500 (comment) it didn't worked for me but maybe for you

@cinc-b
Copy link

cinc-b commented Dec 10, 2022

Ty will take a look!

@vondersam
Copy link

The cleanup function needs to be properly called as it is asynchronous:

const QRScanner = (props: Html5QrcodePluginProps) => {
  const scannerRef = useRef<Html5QrcodeScanner | null>(null);
  const isMounted = useRef(true);

  useEffect(() => {
    const startScanning = async (): Promise<Html5QrcodeScanner> => {
      // Initialize and start the QR scanner
      // when component mounts
      const config = createConfig(props);
      const verbose = props.verbose === true;
      // Suceess callback is required.
      if (!props.qrCodeSuccessCallback) {
        throw 'qrCodeSuccessCallback is required callback.';
      }
      const html5QrcodeScanner = new Html5QrcodeScanner(qrcodeRegionId, config, verbose);
      console.log('render html5QrcodeScanner');
      await html5QrcodeScanner.render(props.qrCodeSuccessCallback, props.qrCodeErrorCallback);
      return html5QrcodeScanner;
    };

    const initScanner = async () => {
      if (isMounted.current) {
        scannerRef.current = await startScanning();
      }
    };

    initScanner();

    // cleanup function when component will unmount
    return () => {
      isMounted.current = false;
      const clearScanner = async () => {
        try {
          if (scannerRef.current) await scannerRef.current.clear();
        } catch (error) {
          console.log('Failed to clear html5QrcodeScanner. ', error);
        }
      };
      clearScanner();
    };
  }, [props]);

  return <div id={qrcodeRegionId} />;
};

export default QRScanner;```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants