diff --git a/src/index.js b/src/index.js index 8dd68e6..8105f22 100644 --- a/src/index.js +++ b/src/index.js @@ -1,122 +1,128 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import PropTypes from 'prop-types' -import WebWorker from 'web-worker:./worker' +import * as React from "react"; +import PropTypes from "prop-types"; +import WebWorker from "web-worker:./worker"; -const createWorker = () => new WebWorker() +const createWorker = () => new WebWorker(); const stopMediaStream = (stream) => { if (stream) { if (stream.getVideoTracks && stream.getAudioTracks) { - stream.getVideoTracks().map(track => { + stream.getVideoTracks().forEach((track) => { stream.removeTrack(track); track.stop(); }); - stream.getAudioTracks().map(track => { + stream.getAudioTracks().forEach((track) => { stream.removeTrack(track); track.stop(); }); - } - else { + } else { stream.stop(); } } -} +}; const Reader = (props) => { - const { constraints, onError, onLoad, onScan, resolution, ...other } = props - const constraintsStr = JSON.stringify(constraints) + const { constraints, onError, onLoad, onScan, resolution, ...other } = props; + const constraintsStr = JSON.stringify(constraints); - const streamRef = useRef(null) - const videoEl = useRef(null) - const canvasEl = useRef(document.createElement('canvas')) - const ctxRef = useRef(null) - const requestRef = useRef() - const [src, setSrc] = useState(null) + const streamRef = React.useRef(null); + const videoEl = React.useRef(null); + const canvasEl = React.useRef(document.createElement("canvas")); + const ctxRef = React.useRef(null); + const requestRef = React.useRef(); + const [src, setSrc] = React.useState(null); - const isProcessingRef = useRef(false) - const worker = useMemo(createWorker, [createWorker]) + const isProcessingRef = React.useRef(false); + const workerRef = React.useRef(); - useEffect(() => { - return () => { - worker.terminate() - } - }, [worker]) + React.useEffect(() => { + workerRef.current = createWorker(); + const worker = workerRef.current; - useEffect(() => { worker.onmessage = (e) => { - if (onScan) onScan(e.data ? { ...e.data, canvas: canvasEl.current } : null) - isProcessingRef.current = false - } - }, [onScan, worker]) + if (onScan) + onScan(e.data ? { ...e.data, canvas: canvasEl.current } : null); + isProcessingRef.current = false; + }; - const check = useCallback(() => { - const videoIsPlaying = videoEl.current && videoEl.current.readyState === videoEl.current.HAVE_ENOUGH_DATA + return () => { + worker.terminate(); + }; + }, [onScan]); + + const check = React.useCallback(() => { + const worker = workerRef.current; + + const videoIsPlaying = + videoEl.current && + videoEl.current.readyState === videoEl.current.HAVE_ENOUGH_DATA; if (!isProcessingRef.current && videoIsPlaying) { - isProcessingRef.current = true + isProcessingRef.current = true; // Get image/video dimensions - let width = videoEl.current.videoWidth - let height = videoEl.current.videoHeight + let width = videoEl.current.videoWidth; + let height = videoEl.current.videoHeight; - const greatestSize = width > height ? width : height - const ratio = resolution / greatestSize + const greatestSize = width > height ? width : height; + const ratio = resolution / greatestSize; - height = ratio * height - width = ratio * width + height = ratio * height; + width = ratio * width; - canvasEl.current.width = width - canvasEl.current.height = height + canvasEl.current.width = width; + canvasEl.current.height = height; - ctxRef.current = canvasEl.current.getContext('2d') - ctxRef.current.drawImage(videoEl.current, 0, 0, width, height) - const imageData = ctxRef.current.getImageData(0, 0, width, height) + ctxRef.current = canvasEl.current.getContext("2d"); + ctxRef.current.drawImage(videoEl.current, 0, 0, width, height); + const imageData = ctxRef.current.getImageData(0, 0, width, height); // Send data to web-worker - worker.postMessage(imageData) + worker.postMessage(imageData); } - requestRef.current = requestAnimationFrame(check) - }, [resolution, worker]) + requestRef.current = requestAnimationFrame(check); + }, [resolution]); - useEffect(() => { - const constraints = JSON.parse(constraintsStr) + React.useEffect(() => { + const constraints = JSON.parse(constraintsStr); - let isSubscribed = true - navigator.mediaDevices.getUserMedia(constraints) + let isSubscribed = true; + navigator.mediaDevices + .getUserMedia(constraints) .then((stream) => { if (!isSubscribed) { - stopMediaStream(stream) + stopMediaStream(stream); } else { - streamRef.current = stream + streamRef.current = stream; try { if (videoEl.current) { - videoEl.current.srcObject = stream - videoEl.current.setAttribute('playsinline', true) // required to tell iOS safari we don't want fullscreen + videoEl.current.srcObject = stream; + videoEl.current.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen } } catch (error) { - setSrc(window.URL.createObjectURL(stream)) + setSrc(window.URL.createObjectURL(stream)); } - if (onLoad) onLoad() + if (onLoad) onLoad(); - requestRef.current = requestAnimationFrame(check) + requestRef.current = requestAnimationFrame(check); } }) - .catch(error => (isSubscribed ? onError(error) : null)) + .catch((error) => (isSubscribed ? onError(error) : null)); return () => { - cancelAnimationFrame(requestRef.current) - isSubscribed = false - stopMediaStream(streamRef.current) + cancelAnimationFrame(requestRef.current); + isSubscribed = false; + stopMediaStream(streamRef.current); if (src) { window.URL.revokeObjectURL(src); } - } - }, [check, constraintsStr, onError, onLoad]) + }; + }, [check, constraintsStr, onError, onLoad, src]); - return (