You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用React qrscan库扫码后无法关闭摄像头重复扫码怎么解决?

问题原因

你使用的qrscan组件未实现卸载时自动释放摄像头媒体流的逻辑,即使通过条件渲染将组件从DOM树移除,后台的摄像头捕获进程仍在运行,绑定的onFind回调会持续被触发,导致重复拿到扫码结果。

解决方案
  • 方案1:通过key属性强制组件完全卸载重建
    React中当组件的key属性发生变化时,会直接销毁旧的组件实例,触发完整的卸载生命周期,清理组件绑定的所有资源。你只需要在渲染QRScan组件时加入动态key即可:
{scanning ? (
  <QRScan key={Date.now()} onFind={onFind} />
) : (
  <>
    <button onClick={() => setScanning(true)}>Scan</button>
    <h4>value: {scannerValue}</h4>
  </>
)}

每次打开扫码时生成新的时间戳作为key,关闭扫码时旧的QRScan实例会被完全销毁,摄像头会自动停止。

  • 方案2:使用组件内置的启停属性
    大部分扫码组件都提供了active/running这类控制扫描状态的属性,不需要通过条件渲染控制组件显示,直接把scanning状态传入对应属性即可:
<QRScan active={scanning} onFind={onFind} />
{!scanning && (
  <>
    <button onClick={() => setScanning(true)}>Scan</button>
    <h4>value: {scannerValue}</h4>
  </>
)}

组件内部会根据传入的状态自动启停摄像头,不需要卸载组件。

  • 方案3:加扫描锁+手动释放摄像头(兜底方案)
    如果前两种方案都无效,可以加一个ref标记是否已经拿到扫码结果,同时在拿到结果后手动停止所有摄像头媒体流:
const [scanning, setScanning] = useState(false);
const [scannerValue, setScannerValue] = useState('');
// 扫描锁,防止重复触发
const scanLocked = useRef(false);

const onFind = (value: string) => {
  // 已经拿到结果就直接返回
  if (scanLocked.current) return;
  scanLocked.current = true;
  setScannerValue(value);
  setScanning(false);
  console.log(value);
  // 手动停止所有视频流
  navigator.mediaDevices.getUserMedia({ video: true })
    .then(stream => {
      stream.getTracks().forEach(track => track.stop());
    })
};

const startScan = () => {
  // 打开扫码前重置锁
  scanLocked.current = false;
  setScanning(true);
};

return (
  {scanning ? (
    <QRScan onFind={onFind} />
  ) : (
    <>
      <button onClick={startScan}>Scan</button>
      <h4>value: {scannerValue}</h4>
    </>
  )}
)

内容的提问来源于stack exchange,提问作者Mihail Iliev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 07:24:04