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

Expo-Camera无法设置扫码间隔,单次扫码触发多次回调问题求助

解决Expo Camera二维码扫描多次触发回调的问题

核心原因

Expo Camera的barcodeSettings.interval仅控制扫描引擎的检测间隔,但在单次检测周期内(比如同一帧画面),扫描引擎可能多次识别到同一个二维码,导致onBarCodeScanned在同一毫秒内连续触发多次,该参数无法解决这类重复触发问题。

解决方案:状态锁+数据去重

通过组件状态控制扫描回调的执行时机,同时记录上一次扫描的二维码数据,避免重复处理同一条码。

修改后的代码示例

import { useState, useCallback } from 'react';
import { View, ToastAndroid } from 'react-native';
import { Camera } from 'expo-camera';

export default function ScannerScreen() {
  const [type, setType] = useState(Camera.Constants.Type.back);
  // 标记是否正在处理扫描结果
  const [isProcessing, setIsProcessing] = useState(false);
  // 记录上一次扫描的二维码数据
  const [lastScannedData, setLastScannedData] = useState('');

  const handleBarCodeScanned = useCallback(async ({ type: typeCode, data }) => {
    // 正在处理或扫描到重复数据时直接返回
    if (isProcessing || data === lastScannedData) return;

    setIsProcessing(true);
    setLastScannedData(data);

    // 执行你的业务逻辑
    console.log("NEW code scanned, Type: " + typeCode + " Data: " + data + " Time scan: " + new Date());
    ToastAndroid.show("scanned", ToastAndroid.SHORT);

    // 1秒后解锁,允许下一次扫描(可根据需求调整时长)
    setTimeout(() => {
      setIsProcessing(false);
      // 可选:5秒后清空历史数据,允许重新扫描同一个二维码
      // setTimeout(() => setLastScannedData(''), 5000);
    }, 1000);
  }, [isProcessing, lastScannedData]);

  return (
    <View style={styles.container}>
      <Camera
        barcodeSettings={{
          interval: 1000, // 保留该参数控制扫描间隔,配合业务层控制双重保障
        }}
        style={styles.camera}
        type={type}
        onBarCodeScanned={handleBarCodeScanned}
        ratio="16:9"
      />
    </View>
  );
}

const styles = {
  container: {
    flex: 1,
  },
  camera: {
    flex: 1,
  },
};

备选方案:防抖函数

如果不想手动管理状态锁,可以使用防抖函数来限制回调的执行频率:

代码示例

import { useCallback } from 'react';
import { debounce } from 'lodash';
// ...其他导入

export default function ScannerScreen() {
  // ...其他状态

  const handleBarCodeScanned = useCallback(debounce(async ({ type: typeCode, data }) => {
    console.log("NEW code scanned, Type: " + typeCode + " Data: " + data + " Time scan: " + new Date());
    ToastAndroid.show("scanned", ToastAndroid.SHORT);
  }, 1000, { 
    leading: true, // 立即执行第一次触发的回调
    trailing: false // 忽略防抖时间内的后续触发
  }), []);

  // ...组件返回部分
}

注意事项

  • 状态锁方案无需额外依赖,更适合小型项目;防抖函数需要安装lodash(npm install lodash)。
  • 调整解锁/防抖的时长时,需平衡用户体验和扫描灵敏度,避免过长导致用户重复扫码无响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:23:15