Illegal constructor
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.
This version can solve your problem.
=== Although this problem can be solved this way, I still ask for code that can reproduce the problem.
I guess some framework/library reasons caused our SDK to be loaded repeatedly.
Thanks for the answer @Keillion I will try to test it today.
Hello @Keillion it looks like 10.4.2002-beta-202410310215 solved the issue we had.
I see it has a beta label. Will this be merged in the next version?
Yes, we plan to merge it in 10.6.x.
You can just use this beta version. We will support it.
Thanks for your help :) Closing.
I keep showing this bug until we fix it in a official release.