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

Expo-Camera的onCameraReady触发异常:仅关闭相机或加console.log时执行

Expo-Camera onCameraReady 触发异常问题解决方法

核心解决思路

别依赖console.log这种临时hack,本质是React状态更新和相机硬件初始化的时序冲突问题。换个思路:用useEffect配合相机激活状态来处理比例检测,避开onCameraReady里的同步逻辑阻塞。

完整修复代码示例

import React, { useState, useRef, useEffect } from 'react';
import { View, Text, Dimensions } from 'react-native';
import { Camera } from 'expo-camera';

export default function QRCodeScanner() {
  const [hasPermission, setHasPermission] = useState(null);
  const [cameraRatio, setCameraRatio] = useState('4:3');
  const cameraRef = useRef(null);
  const [cameraIsReady, setCameraIsReady] = useState(false);
  const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
  const screenRatio = screenHeight / screenWidth;

  // 请求相机权限
  useEffect(() => {
    (async () => {
      const { status } = await Camera.requestCameraPermissionsAsync();
      setHasPermission(status === 'granted');
    })();
  }, []);

  // 相机就绪后再检测最优比例
  useEffect(() => {
    if (cameraIsReady && cameraRef.current) {
      const fetchOptimalRatio = async () => {
        const supportedRatios = await cameraRef.current.getSupportedRatiosAsync();
        // 筛选和屏幕比例最接近的相机比例
        const bestRatio = supportedRatios.reduce((best, curr) => {
          const [w, h] = curr.split(':').map(Number);
          const ratio = h / w;
          return Math.abs(ratio - screenRatio) < Math.abs(best.ratio - screenRatio)
            ? { ratio, value: curr }
            : best;
        }, { ratio: Infinity, value: supportedRatios[0] });
        setCameraRatio(bestRatio.value);
      };
      fetchOptimalRatio();
    }
  }, [cameraIsReady, screenRatio]);

  const handleCameraReady = () => {
    // 只做状态标记,不处理复杂逻辑
    setCameraIsReady(true);
  };

  if (hasPermission === null) return <View />;
  if (hasPermission === false) return <Text>没有相机权限,请在设置中开启</Text>;

  return (
    <Camera
      ref={cameraRef}
      style={{ flex: 1 }}
      ratio={cameraRatio}
      onCameraReady={handleCameraReady}
      type={Camera.Constants.Type.back}
    />
  );
}

问题根源解释

  • Expo-Camera的onCameraReady在相机硬件刚初始化完成时触发,但如果回调里直接做同步状态更新或异步请求,可能会因为React的批量更新机制,导致后续逻辑被吞掉。
  • 加console.log能临时解决,是因为它触发了JS引擎的微任务调度,把后续逻辑推到事件循环的下一轮,此时相机状态已经完全稳定,所以能正常执行。但这只是巧合,不是正经解决方案。

额外适配技巧

  • 不要硬编码比例,根据当前设备的屏幕宽高比去匹配相机支持的比例,这样能保证预览画面完全铺满屏幕,不会变形。
  • 如果还是遇到时序问题,可以在useEffect里加个100ms左右的微小延迟(极端情况可用,不推荐作为常规方案):
useEffect(() => {
  if (cameraIsReady && cameraRef.current) {
    const timer = setTimeout(async () => {
      // 比例检测逻辑
    }, 100);
    return () => clearTimeout(timer);
  }
}, [cameraIsReady]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 03:48:22