mebjas / html5-qrcode

A cross platform HTML5 QR code reader. See end to end implementation at: https://scanapp.org
https://qrcode.minhazav.dev
Apache License 2.0
5.06k stars 976 forks source link

Cannot transition to a new state, already under transition #756

Open TulioMeran opened 1 year ago

TulioMeran commented 1 year ago

Describe the bug

I'm trying to implement the library in React, the app is working as expected until i try to scan the same qr code twice, when i do i get this error:

Cannot transition to a new state, already under transition

Here is my code:

import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { Html5QrcodeScanner } from 'html5-qrcode';

const qrcodeRegionId = 'html5qr-code-full-region';

interface IBarcodeScannerProps {
  fps?: number;
  qrbox?: number;
  aspectRatio?: number;
  verbose?: boolean;
  disableFlip?: boolean;
  supportedScanTypes?: Array<number>;
  qrCodeSuccessCallback: (data: string) => void;
  qrCodeErrorCallback?: (error: string) => void;
}

interface configPropsT {
  fps: number;
  qrbox?: number;
  aspectRatio?: number;
  disableFlip?: boolean;
  supportedScanTypes: Array<number>;
}

const BarcodeScanner: FC<IBarcodeScannerProps> = ({
  fps = 10,
  qrbox,
  aspectRatio,
  verbose = false,
  disableFlip,
  supportedScanTypes = [0, 1],
  qrCodeSuccessCallback,
  qrCodeErrorCallback,
}) => {
  const [scanner, updateScanner] = useState<Html5QrcodeScanner>();
  const [scannerLoaded, updateScannerLoaded] = useState(false);
  const [scannedData, updateScannedData] = useState('');

  const handleSuccess = useCallback(
    (data: string) => {
      if (scanner && scanner.pause) {
        scanner.pause();
      }

      updateScannedData(data);
      qrCodeSuccessCallback(data);
    },
    [scanner, qrCodeSuccessCallback],
  );

  const handleError = useCallback(
    (error: string) => {
      if (qrCodeErrorCallback) {
        qrCodeErrorCallback(error);
      }
    },
    [qrCodeErrorCallback],
  );

  const configProps: configPropsT = useMemo(() => {
    return {
      fps,
      ...(qrbox && { qrbox }),
      ...(aspectRatio && { aspectRatio }),
      ...(disableFlip && { disableFlip }),
      ...(supportedScanTypes && { supportedScanTypes }),
    };
  }, [fps, qrbox, aspectRatio, disableFlip, supportedScanTypes]);

  useEffect(() => {
    // Success callback is required.
    if (!qrCodeSuccessCallback) {
      console.log('qrCodeSuccessCallback is required callback.');
    }

    if (!scannerLoaded) {
      updateScanner(new Html5QrcodeScanner(qrcodeRegionId, configProps, verbose));

      updateScannerLoaded(true);
    }

    return () => {
      //Cleanup
      if (scanner) {
        scanner.clear().catch((error) => {
          console.error('Failed to clear html5QrcodeScanner. ', error);
        });
      }
    };
  }, [qrCodeSuccessCallback, scannerLoaded, configProps, verbose, scanner]);

  useEffect(() => {
    if (scanner) {
      scanner.render(handleSuccess, handleError);
    }
  }, [scanner, handleSuccess, handleError]);

  return (
    <div>
      <div id={qrcodeRegionId}  style={{ maxWidth: '500px', margin: 'auto' }} />
      {scannedData && <div>UPC Number :{scannedData}</div>}
    </div>
  );
};

export default BarcodeScanner;

Screenshots

image

cxxerry commented 1 year ago

use await