浏览器扫码听起来像是个「有手就行」的需求——直到你在生产环境看到 React 报错Node.removeChild: The node to be removed is not a child of this node。这不是你的代码问题,是两个运行时争夺 DOM 控制权的经典翻车现场。
最近用html5-qrcode给 Next.js 项目做扫码功能,踩了三个深坑。这篇把完整的事件线还原一遍,包括那个让我调试到凌晨两点的竞态条件。
选型:为什么不是 zxing-js 或 jsQR
浏览器扫码有三条技术路线:zxing-js功能全但 API 繁琐,jsQR轻量却得自己处理摄像头权限和帧循环,html5-qrcode把这两层都包了。对于不想维护getUserMedia兼容层的产品团队,这是唯一理性的选择。
安装命令一行:
npm install html5-qrcode
架构设计很简单:同一个Html5Qrcode实例,图片上传走scanFile(),实时摄像头走start()。代码层面区分调用方式即可,核心逻辑复用。
但纸面架构和真实 DOM 是两回事。
第一崩:React 与第三方库的 DOM 战争
最初的实现很直觉:用 React 状态控制摄像头容器的显隐。
{cameraActive && (
问题在html5-qrcode的工作机制。调用start()后,库会往#qr-camera-feed里注入、和若干内部
。这些节点不在 React 的虚拟 DOM 里。
当用户关闭摄像头,cameraActive置为false,React 尝试卸载它记忆中的那个#qr-camera-feed。但真实 DOM 已经被库改得面目全非——React 找不到它以为存在的子节点,直接抛异常。
![]()
修复方案是彻底放弃 React 对容器内部的控制:
{/* 提示层和摄像头层完全分离 */}
{!cameraActive && (
点击启动摄像头
关键点:容器永远挂载,只用 CSS 控制可见性。库对 DOM 的修改被限制在一个 React 不会触碰的隔离区内。
第二崩:扫码成功时的竞态条件
第一个坑修好后,功能跑通了——直到测试发现偶发的崩溃。
复现路径:二维码进入画面 → 成功回调触发 → 回调里调用stopCamera()→scanner.stop()执行 → 库内部还在处理刚才那一帧 → 状态不一致。
根本原因是html5-qrcode的start()是异步的,但很多人以为它返回时扫描就已经就绪。实际上,内部引擎还在预热,帧处理循环和回调注册存在时间窗口。
解决方案是用 ref 做运行状态守卫:
const scannerRef = useRef(null);
const scannerRunningRef = useRef(false);
启动流程:
![]()
await scanner.start(...);
scannerRunningRef.current = true; // 必须在 start() resolve 之后
停止流程:
if (scannerRunningRef.current) {
scannerRunningRef.current = false;
await scanner.stop();
}
这个 flag 的作用不是性能优化,是防止重复停止和状态错乱。扫码成功回调里第一件事就是检查并置 false,再执行业务逻辑。
第三坑:图片扫描的内存泄漏
图片上传模式看起来更安全——没有摄像头流,没有实时回调。但scanFile()内部会创建临时的Image对象和 canvas 上下文,大文件或批量扫描时内存曲线会缓慢爬升。
库文档没提的是,scanFile()的第二个参数showImage如果设为true,会在 DOM 里留一个预览图节点。如果你用 React 管理预览 UI,这个内部节点就成了孤儿。
统一的做法:第二个参数永远传false,预览层自己用URL.createObjectURL()实现,扫描完手动revokeObjectURL()。
三个坑的共同主题:第三方库和 React 的边界管理。
浏览器扫码这个需求,表面是 CV 代码,实际是运行时协调。html5-qrcode 把底层复杂度包得很好,但包不住它和 React 在 DOM 所有权上的根本冲突。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.