Implementing QR code scanning in modern web applications has become essential for various use cases. This guide demonstrates a robust implementation using Next.js and react-qrcode-scanner with proper camera management.
"use client";
import React, { useEffect, useRef, useState } from "react";
import { QrScanner } from "react-qrcode-scanner";
interface QRCodeScannerProps {
onScanSuccess: (value: string) => void;
scanDelay?: number;
}
const QRCodeScanner = ({
onScanSuccess,
scanDelay = 500,
}: QRCodeScannerProps) => {
const [cameraReady, setCameraReady] = useState(false);
const [error, setError] = useState<string | null>(null);
const streamRef = useRef<MediaStream | null>(null);
useEffect(() => {
const initCamera = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: "environment" },
});
streamRef.current = stream;
setCameraReady(true);
} catch (err) {
setError("Camera access denied or unavailable");
console.error("Camera initialization error:", err);
}
};
initCamera();
return () => {
if (streamRef.current) {
streamRef.current.getTracks().forEach((track) => track.stop());
}
};
}, []);
const handleScan = (value: string | null) => {
if (value) {
onScanSuccess(value);
}
};
const handleError = (err: Error) => {
setError("Scanner error: " + err.message);
console.error("QR Scanner error:", err);
};
return (
<div className="scanner-container">
{error ? (
<div className="scanner-error">
{error}
<button onClick={() => window.location.reload()}>Retry</button>
</div>
) : cameraReady ? (
<QrScanner
delay={scanDelay}
onScan={handleScan}
onError={handleError}
constraints={{ facingMode: "environment" }}
className="scanner-view"
/>
) : (
<div className="scanner-loading">Initializing camera...</div>
)}
</div>
);
};
export default QRCodeScanner;
<QRCodeScanner onScanSuccess={onScanSuccess} scanDelay={scanDelay} />
Add seamless QR code scanning capabilities to your web projects with this production-ready implementation.