Skip to content

Illegal constructor #154

@regisoc

Description

@regisoc

Hello,

Short version: maybe I am just blind after some hours spent on that. There is an annoying "Illegal constructor" appearing and I cannot figure out why.

I am trying to set up the React VideoCapture element as mentioned here.

It looks like this:

`VideoCapture` element
import React from 'react';

import '../dynamsoft.config';

// --Change starts
// For some reason, import from Dynamsoft does not work. But the library is creating a global
// `Dynamsoft` object that has all the library contents.

// @ts-ignore
import "dynamsoft-camera-enhancer";
// @ts-ignore
import "dynamsoft-capture-vision-router";
// @ts-ignore
import "dynamsoft-utility";

const Dynamsoft = (window as any).Dynamsoft;
const CameraEnhancer = Dynamsoft.DCE.CameraEnhancer;
const CameraView = Dynamsoft.DCE.CameraView;
const CaptureVisionRouter = Dynamsoft.CVR.CaptureVisionRouter;
const MultiFrameResultCrossFilter = Dynamsoft.Utility.MultiFrameResultCrossFilter;

// -- Change end

const componentDestroyedErrorMsg = "VideoCapture Component Destroyed";

class VideoCapture extends React.Component<{ onSubmit: Function }, {}> {
  cameraViewContainer: React.RefObject<HTMLDivElement> = React.createRef();

  resolveInit?: () => void;
  pInit: Promise<void> = new Promise((r) => (this.resolveInit = r));
  isDestroyed = false;

  cvRouter?: typeof Dynamsoft.CVR;
  cameraEnhancer?: typeof Dynamsoft.CE;

  async componentDidMount() {
    try {
      // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control.
      const cameraView = await CameraView.createInstance();
      if (this.isDestroyed) {
        throw Error(componentDestroyedErrorMsg);
      } // Check if component is destroyed after every async

      this.cameraEnhancer = await CameraEnhancer.createInstance(cameraView);
      if (this.isDestroyed) {
        throw Error(componentDestroyedErrorMsg);
      }

      // Get default UI and append it to DOM.
      this.cameraViewContainer.current!.append(cameraView.getUIElement());

      // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source.
      this.cvRouter = await CaptureVisionRouter.createInstance();
      if (this.isDestroyed) {
        throw Error(componentDestroyedErrorMsg);
      }
      this.cvRouter.setInput(this.cameraEnhancer);

      // Define a callback for results.
      this.cvRouter.addResultReceiver({
        onDecodedBarcodesReceived: (result: any) => {
          if (!result.barcodeResultItems.length) return;

          for (let item of result.barcodeResultItems) {
            this.props.onSubmit(item.text);
          }
        },
      });

      // Filter out unchecked and duplicate results.
      const filter = new MultiFrameResultCrossFilter();
      // Filter out unchecked barcodes.
      filter.enableResultCrossVerification("barcode", true);
      // Filter out duplicate barcodes within 3 seconds.
      filter.enableResultDeduplication("barcode", true);
      await this.cvRouter.addResultFilter(filter);
      if (this.isDestroyed) {
        throw Error(componentDestroyedErrorMsg);
      }

      // Open camera and start scanning single barcode.
      await this.cameraEnhancer.open();
      if (this.isDestroyed) {
        throw Error(componentDestroyedErrorMsg);
      }
      await this.cvRouter.startCapturing("ReadSingleBarcode");
      if (this.isDestroyed) {
        throw Error(componentDestroyedErrorMsg);
      }
    } catch (ex: any) {
      if ((ex as Error)?.message === componentDestroyedErrorMsg) {
        console.log(componentDestroyedErrorMsg);
      } else {
        let errMsg = ex.message || ex;
        console.error(errMsg);
        console.log("ERROR HERE");
        console.log(ex);
        alert(errMsg);
      }
    }

    // Resolve pInit promise once initialization is complete.
    this.resolveInit!();
  }

  async componentWillUnmount() {
    this.isDestroyed = true;
    try {
      // Wait for the pInit to complete before disposing resources.
      await this.pInit;
      this.cvRouter?.dispose();
      this.cameraEnhancer?.dispose();
    } catch (_) {}
  }

  shouldComponentUpdate() {
    // Never update UI after mount, sdk use native way to bind event, update will remove it.
    return false;
  }

  render() {
    return (
      <div ref={this.cameraViewContainer} style={{  width: "100%", height: "70vh" }}></div>
    );
  }
}

export default VideoCapture;

The VideoCapture component is embedded is another QRCodeReader element.

`QRCodeReader` element
import { useState } from 'react';
import VideoCapture from "./VideoCapture";

const QRCodeReader = (props) => {
    const [errors, setErrors] = useState(null);

    const onSubmit = async (param) => {
        try {
            const isUpdated = await props.onSubmit(param);
            if (isUpdated) {
                setErrors(null);
            }
        } catch(error){
            setErrors(error);
        }
    }

    return (
        <div>
            <VideoCapture onSubmit={onSubmit} />
            {errors}
        </div>
    );
}

export default QRCodeReader;

Until here, everything works well. Using the QRCodeReader element, it can scan QRCode and extract the item elements. Nice.

The issue happens after that, when I try to embed the QRCodeReader element into a QRModal Element.
Elements looks like this VideoCapture <- QRCodeReader <- QRModal.

We want to use them in a process that is the following:

  • first scan: uses the QRCodeReader (full page reader).
  • updates the page to match info in the QRCode, loads a list of items from db on the page, each item has a scan modal button to trigger the QRModal, to access the detail of each item, we must scan again using the modal.
  • second scan: uses the QRModal (modal reader) -> fails consistently with the same error.
`QRModal` element
import React, {useEffect, useState} from 'react';
import PropTypes from 'prop-types';
import Modal from 'Modal';
import QRCodeReader from './QRCodeReader';

/**
 * Widget to access a profile using a QR code
 *
 * @param {object} props - React props
 *
 * @return {ReactDOM}
 */
const QRModal = (props) => {
  const [code, setCode] = useState(null);

  useEffect(() => {
  }, []);

  return (
    <Modal
      onClose={() => {
        props.onClose();
      }}
      show={true}
      title={props.modalTitle}
    >
      <QRCodeReader onSubmit={(c) => {
        if (c === code) return;
        setCode(c);
        props.onScan(c);
      }} />
    </Modal>
  );
}

QRModal.defaultProps = {
  modalTitle: 'Scan QR Code',
};

QRModal.propTypes = {
  modalTitle: PropTypes.string,
};

export default QRModal;

This is throwing a Type Error: Illegal constructor. apparently coming from CameraView.createInstance().

I also tried to directly shortcut QRModal to directly call another VideoCapture class (VideoCapture2 is a copy of VideoCapture). Same result.

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions