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

React项目中Html5Qrcode组件卸载时无法停止相机的问题

React中Html5Qrcode路由跳转时无法停止相机的解决方案

问题背景

在React应用中使用Html5Qrcode包实现扫码功能,扫码成功后调用html5QrCode.stop()可正常停止扫描,但当用户未完成扫码就进行路由跳转(返回、切换URL等)时,相机仍会在后台持续运行,无视频画面却占用系统资源。

尝试通过componentWillUnmount生命周期处理相机停止逻辑时,出现错误:Uncaught TypeError: Cannot set properties of undefined (setting 'element'),原代码中在componentWillUnmount里重新实例化Html5Qrcode,导致DOM元素已卸载时实例化失败。

错误原因

  1. componentDidMount中创建的html5QrCode是局部变量,组件其他生命周期无法访问,只能重新实例化,但此时DOM元素qr-reader可能已被销毁,实例化失败。
  2. 直接调用Html5Qrcode("qr-reader")并非正确的实例获取方式,应该复用组件内已创建的实例。

修复步骤

  • 在组件类中保存html5QrCode实例,通过组件实例属性共享,避免局部变量无法访问的问题。
  • 在componentWillUnmount中先判断实例是否存在,再调用stop()方法,确保异步操作的错误被捕获。
  • 确保组件卸载时,直接通过已保存的实例停止扫描,无需依赖已销毁的DOM元素。

修复后的完整代码

import React, { Component } from 'react';
import { Html5Qrcode } from 'html5-qrcode';

export default class Scanner extends Component {
  constructor(props) {
    super(props);
    this.state = {
      availableCameras: []
    };
    // 初始化实例变量,用于保存Html5Qrcode实例
    this.html5QrCode = null;
  }

  handleChange(event) {
    this.setState({
      [event.target.name]: event.target.value
    });
  }
  
  componentDidMount() {
    Html5Qrcode.getCameras().then(devices => {
      this.setState({ availableCameras: devices });
      // 将实例赋值给组件属性,方便后续生命周期访问
      this.html5QrCode = new Html5Qrcode("qr-reader");

      this.html5QrCode.start(
        { facingMode: "environment" },
        {
          fps: 2,
          qrbox: 250
        },
        qrCodeMessage => {
          // 扫码成功后停止扫描
          this.html5QrCode.stop().then(() => {
            console.log("扫码成功,已停止扫描");
          }).catch(err => {
            console.log("停止扫描失败:", err);
          });
          this.props.returnedInfo(qrCodeMessage);
        },
        errorMessage => {
          // 忽略常规的扫码失败错误
          console.log(`未检测到二维码: ${errorMessage}`);
        }
      ).catch(err => {
        console.log(`启动扫描失败: ${err}`);
      });
    }).catch(error => {
      console.log("获取相机列表失败:", error);
    });
  }

  componentWillUnmount() {
    // 检查实例是否存在,避免空指针错误
    if (this.html5QrCode) {
      this.html5QrCode.stop().then(() => {
        console.log("组件卸载,已停止相机扫描");
      }).catch(error => {
        console.log("组件卸载时停止扫描失败:", error);
      });
    }
  }

  render() {
    return <div id="qr-reader" />;
  }
}

函数组件版本补充

如果使用React函数组件,可通过useRef保存Html5Qrcode实例,并在useEffect的清理函数中执行停止逻辑:

import React, { useEffect, useRef } from 'react';
import { Html5Qrcode } from 'html5-qrcode';

const Scanner = ({ returnedInfo }) => {
  const html5QrCodeRef = useRef(null);

  useEffect(() => {
    Html5Qrcode.getCameras().then(devices => {
      html5QrCodeRef.current = new Html5Qrcode("qr-reader");
      html5QrCodeRef.current.start(
        { facingMode: "environment" },
        { fps: 2, qrbox: 250 },
        qrCodeMessage => {
          html5QrCodeRef.current.stop().then(() => {
            console.log("扫码成功,已停止扫描");
          });
          returnedInfo(qrCodeMessage);
        },
        errorMessage => {
          console.log(`未检测到二维码: ${errorMessage}`);
        }
      ).catch(err => {
        console.log(`启动扫描失败: ${err}`);
      });
    }).catch(error => {
      console.log("获取相机列表失败:", error);
    });

    // 组件卸载时停止扫描
    return () => {
      if (html5QrCodeRef.current) {
        html5QrCodeRef.current.stop().catch(error => {
          console.log("组件卸载时停止扫描失败:", error);
        });
      }
    };
  }, [returnedInfo]);

  return <div id="qr-reader" />;
};

export default Scanner;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 22:45:32