Search code examples
reactjstypescriptionic-frameworkqr-code

How to stop (camera of) react-qr-reader


I am using the react-qr-reader component to build a qr scanner modal for my website.

The modal is created as expected and I can scan different qr codes but after dismissing the ion-modal the scanner keeps the users camera active but stops detecting qr codes.

How can I deactivate the users camera?

In my research I found the following question already asked. There the close function I am using is proposed with

ref.current.stopCamera()

at the end. Somehow I can not define ref because ref is not in "IntrinsicAttributes & QrReaderProps" of the QrReader component.

So, how can I reference the react component and is the close function with the added

ref.current.stopCamera()

the correct way of deactivation the camera?

Thanks for your help!

Here is my code:

export const ScannerModal: React.FC<ScannerProps> = ({ triggerID, handleScannedNode }) => {
  const modal = useRef<HTMLIonModalElement>(null);
  const scannerConstraints: MediaTrackConstraints = {

  }

  function onDissMiss(event: CustomEvent<OverlayEventDetail>){
    console.log(event)
    close()
  }

  function handleScan(result: string){
    close()
    handleScannedNode(result)
  }

  async function close(){
    console.log("closing")
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: false,
      video: true,
  });
  stream.getTracks().forEach(function (track) {
      track.stop();
      track.enabled = false;
  });
  //ref.current.stopCamera()
  }

  return (
  <>
  <IonModal trigger={triggerID} onWillDismiss={onDissMiss} ref={modal}>
    <IonTitle>Scanne einen QR-Code</IonTitle>
    <IonPage>
    <QrReader constraints={scannerConstraints} ref={}
        onResult={(result, error) => {
          if (!!result) {
            handleScan(result?.getText());
          }

          if (!!error) {
            //console.info(error);
          }
        }}/>
    </IonPage>
  </IonModal>
  </>
  );
};

I tried referencing the QrReader component via:

const reader = useRef(null);

<QrReader constraints={scannerConstraints} ref={reader}
        onResult={(result, error) => {
          if (!!result) {
            handleScan(result?.getText());
          }

          if (!!error) {
            //console.info(error);
          }
        }}/>

The error I received was:

Property 'ref' does not exist on type 'IntrinsicAttributes & QrReaderProps'.

Solution

  • For everybody finding this thread wanting to just implement a simple react qr scanner:

    I found a working solution using this qr-scanner project.

    I build my component like this:

    import { useRef, useState, useEffect } from 'react';   
    import { IonModal, IonPage, IonTitle } from '@ionic/react';
    import { OverlayEventDetail } from '@ionic/core'; 
    import QrScanner from 'qr-scanner';
    
    interface ScannerProps {
      triggerID: string;
    }
    
    const QrModal: React.FC<ScannerProps> = ({ triggerID }) => {
      const modal = useRef<HTMLIonModalElement>(null);
      const video = useRef<HTMLVideoElement>(null);
      const [qrScanner, setQrScanner] = useState<QrScanner>();
    
      function onDissMiss(_event: CustomEvent<OverlayEventDetail>) {
        close();
      }
    
      function handleScan(result: QrScanner.ScanResult) {
        //Logic with scanned qr code
      }
    
      async function close() {
        qrScanner?.stop();
        qrScanner?.destroy();
        setQrScanner(undefined);
      }
    
      useEffect(() => {
        if (video.current) {
          const qrScanner = new QrScanner(video.current, (result) => handleScan(result), {
            highlightScanRegion: true,
          });
          qrScanner.start();
          setQrScanner(qrScanner);
        }
        // Dependency array missing handleScan, since it should not set Scanner on handleScan change
        // eslint-disable-next-line
      }, [video.current]);
    
      return (
        <>
          <IonModal trigger={triggerID} onWillDismiss={onDissMiss} ref={modal}>
            <IonTitle>Scan your QR-Code</IonTitle>
            <IonPage>
              <video ref={video}></video>
            </IonPage>
          </IonModal>
        </>
      );
    };
    
    export default QrModal;