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

Expo项目expo-barcode-scanner扫码无返回结果问题排查

问题排查结论

扫码无结果是代码逻辑错误导致,和expo-barcode-scanner模块、权限配置无关,核心问题如下:

  • handleBarCodeScanned事件回调未接收扫码返回的{type, data}参数,且错误地将UI渲染逻辑写在事件回调内——事件回调仅负责处理触发后的业务逻辑,不能直接return组件,所有UI内容必须写在组件的render返回结构中。
  • 从Context解构取值时遗漏了getProducts方法,扫码成功后根本没有触发商品查询接口。
  • 列表渲染的products.map箭头函数未return组件,即使有数据也无法渲染;同时OpenFoodFacts接口返回结构无res.data.items字段,取值路径错误,该接口默认返回单个商品对象而非商品数组。
  • 根容器未设置flex:1样式,部分机型上扫码预览区域尺寸异常,无法正常识别条码。

修正后代码

1. ScanScreen.js

import React, { useState, useEffect, useContext  } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import OpenFoodContext from '../../context/openfood/openfoodContext'
import Spinner from '../../components/Spinner';

const ScanScreen = () => {
  // 从Context中解构出查询商品的方法
  const openFoodContext = useContext(OpenFoodContext);
  const { products, loading, getProducts } = openFoodContext;

  const [hasPermission, setHasPermission] = useState(null);
  const [scanned, setScanned] = useState(false);
  const [scanResult, setScanResult] = useState('');

  useEffect(() => {
    (async () => {
      const { status } = await BarCodeScanner.requestPermissionsAsync();
      setHasPermission(status === 'granted');
    })();
  }, []);

  // 扫码回调必须接收扫描返回的类型、条码值参数
  const handleBarCodeScanned = ({ type, data }) => {
    setScanned(true);
    setScanResult(`识别到条码:${data},类型:${type}`);
    // 传入扫到的条码查询商品信息
    getProducts(data);
  };

  if (hasPermission === null) {
    return <Text>正在申请相机权限</Text>;
  }
  if (hasPermission === false) {
    return <Text>未获得相机访问权限,请在系统设置中开启</Text>;
  }

  return (
    <View style={styles.container}>
      <BarCodeScanner
        onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
        style={StyleSheet.absoluteFillObject}
      />
      {/* 所有UI渲染逻辑放在JSX结构中,不要写在事件回调里 */}
      {loading ? <Spinner /> : (
        <View style={styles.resultArea}>
          <Text style={styles.scanText}>{scanResult}</Text>
          {products.length > 0 && products.map((product, index) => (
            // map渲染列表必须return组件,同时添加唯一key
            <Text key={index} style={styles.productText}>{product?.product_name || '未查询到商品名'}</Text>
          ))}
        </View>
      )}
      {scanned && !loading && (
        <Button 
          title={'点击重新扫码'} 
          onPress={() => {
            setScanned(false);
            setScanResult('');
          }} 
        />
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    position: 'relative'
  },
  resultArea: {
    position: 'absolute',
    bottom: 120,
    left: 20,
    right: 20,
    backgroundColor: 'rgba(0,0,0,0.7)',
    padding: 16,
    borderRadius: 8
  },
  scanText: {
    color: '#fff',
    fontSize: 16,
    marginBottom: 12
  },
  productText: {
    color: '#fff',
    fontSize: 14
  }
})

export default ScanScreen;

2. OpenFoodState.js

import  React, {useReducer} from 'react';
import axios from 'axios';
import OpenFoodContext from './openfoodContext';
import OpenFoodReducer from './openfoodReducer';
import {
    GET_ITEMS,
    SET_LOADING,
} from '../types';

const OpenFoodState = props => {
    const initialState ={
        products: [],
        loading: false
    }

    const [state, dispatch] = useReducer(OpenFoodReducer, initialState);

    // 接收扫码得到的条码作为查询参数
    const getProducts = async (barcode) => {
        setLoading();
        try {
          const res = await axios.get(
            `https://world.openfoodfacts.org/api/v0/product/${barcode}.json`
          );
          // 修正接口取值路径,该接口返回单个商品对象,包装为数组适配列表渲染逻辑
          const productData = res.data.product ? [res.data.product] : [];
          dispatch({
              type: GET_ITEMS,
              payload: productData
          });
        } catch (err) {
          console.log('商品查询失败', err);
          dispatch({
            type: GET_ITEMS,
            payload: []
          })
        }
    };

    const setLoading = () => dispatch ({type: SET_LOADING});

    return <OpenFoodContext.Provider
    value={{
        products: state.products,
        loading: state.loading,
        getProducts
    }}
    >
        {props.children}
    </OpenFoodContext.Provider>
}

export default OpenFoodState;

3. openfoodReducer

原有逻辑无错误,无需修改。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:45:59