React模态框中使用react-qr-barcode-scanner实现扫码功能异常问题排查
问题根源分析
你的问题核心在于Bootstrap模态框初始状态是隐藏的:当QR组件在隐藏的模态框内挂载时,react-qr-barcode-scanner会尝试初始化摄像头并渲染视频元素,但此时视频容器处于display: none的不可见状态,浏览器会限制摄像头的访问权限,或者组件无法正确完成视频流的初始化,最终导致扫码功能失效。
另外你的useEffect还存在一个小问题:没有设置依赖数组,这会导致组件每次渲染时都触发这个副作用,进而引发不必要的路由跳转循环;而且history.go()是多余的,history.push()已经会触发路由更新。
解决方案
我们可以通过监听Bootstrap模态框的显示事件,在模态框完全显示后再挂载扫码组件,确保视频元素可见时才初始化摄像头。同时修复useEffect的依赖问题。
步骤1:修改主组件,添加模态框显示监听
用状态控制QR组件的渲染,只有当模态框显示后才渲染它:
import React, { useEffect, useState} from "react"; import ReactDOM from 'react-dom'; import { useHistory, BrowserRouter } from "react-router-dom"; import BarcodeScannerComponent from "react-qr-barcode-scanner"; const QR = () => { const [data, setData ] = useState('Not Found'); const history = useHistory(); // 修复useEffect依赖,仅在data变化时触发 useEffect(() => { if(data !== 'Not Found') { history.push(data); // 移除多余的history.go() } }, [data, history]) // 添加依赖数组 return ( <> <BarcodeScannerComponent width={500} height={500} onUpdate={(err, result) => { if (result) { setData(result.text); } else setData("Not Found"); }} /> <p>{data}</p> </> ); } const App = () => { const [modalShown, setModalShown] = useState(false); useEffect(() => { // 监听Bootstrap模态框的显示/隐藏事件 const modalElement = document.getElementById('qr-modal'); const handleModalShown = () => setModalShown(true); const handleModalHidden = () => setModalShown(false); modalElement.addEventListener('shown.bs.modal', handleModalShown); modalElement.addEventListener('hidden.bs.modal', handleModalHidden); // 组件卸载时清理监听 return () => { modalElement.removeEventListener('shown.bs.modal', handleModalShown); modalElement.removeEventListener('hidden.bs.modal', handleModalHidden); }; }, []); return ( <> <button type="button" className="btn btn-primary" data-toggle="modal" data-target="#qr-modal"> <i className="fas fa-qrcode"></i> </button> <div className="modal fade" id="qr-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div className="modal-dialog" role="document"> <div className="modal-content"> <div className="modal-header"> <h5 className="modal-title" id="exampleModalLabel">扫码跳转</h5> <button type="button" className="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div className="modal-body"> {/* 仅在模态框完全显示后才渲染扫码组件 */} {modalShown && <QR />} </div> <div className="modal-footer"> <button type="button" className="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div> </> ) } ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById('qr-id') );
关键修改点说明:
- 模态框显示监听:通过Bootstrap的
shown.bs.modal事件判断模态框是否完全显示,此时再渲染QR组件,确保扫码组件初始化时视频元素是可见的,浏览器能正常授予摄像头权限。 - 修复useEffect依赖:给
useEffect添加[data, history]依赖数组,避免不必要的重复触发;同时移除了多余的history.go()。 - 规范React属性写法:将
class改为React标准的className属性,避免潜在的兼容性问题。
内容的提问来源于stack exchange,提问作者Áron Pop Adorján
相关产品推荐
相关产品推荐

