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

Expo BarCodeScanner导航返回后相机持续开启未关闭问题

问题根因

相机资源无法释放的核心原因有三点:

  • react-navigation Stack 导航默认缓存所有访问过的页面实例,页面返回上一级时不会触发组件卸载,你之前用children传入render prop的写法不会改变默认缓存逻辑,相机组件实例会一直留在内存中。
  • 仅靠useIsFocused做条件渲染无法彻底回收Expo BarCodeScanner的原生相机资源:该组件原生层的相机占用不会仅因为JS层移除节点就释放,必须配合组件卸载逻辑才能完全断开占用。
  • 原有组件存在逻辑bug:hasPermission初始值设为undefined,但加载态判断写的是hasPermission === null,该判断永远不会命中,会导致权限未授权完成时就提前初始化相机。
修复方案

1. 修改导航配置,开启页面失焦自动卸载

给QR扫描页的Stack.Screen添加unmountOnBlur: true配置,让页面离开导航栈视图时自动销毁组件实例,替换原有children传参写法,直接用component属性绑定组件即可:

<NavigationContainer fallback={<Text>Loading...</Text>}>
  <Stack.Navigator
    screenOptions={({ route, navigation }) => ({
      headerShadowVisible: false,
      headerTitle: () => (
        <Text
          style={{
            fontSize: 30,
            fontFamily: Font["900"],
          }}
        >
          Test
        </Text>
      ),
      headerRight: () =>
        route.name !== "QR" ? (
          <Pressable onPress={() => navigation.navigate("QR")}>
            <QrcodeIcon size={26} color="black" />
          </Pressable>
        ) : null,
    })}
  >
    <Stack.Screen name="Home" component={Home} />
    <Stack.Screen 
      name="QR" 
      component={QRCode} 
      options={{ unmountOnBlur: true }}
    />
  </Stack.Navigator>
</NavigationContainer>

注意:unmountOnBlur是@react-navigation/native-stack的支持属性,如果你用的是旧版JS实现的@react-navigation/stack,建议替换为native-stack,原生栈对资源释放的处理更稳定,性能也更好。

2. 修复QRCode组件逻辑,补全状态判断和资源回收

修复权限判断的bug,保留聚焦状态判断作为双重保险,监听页面失焦事件重置扫描状态,确保相机实例可以正常销毁:

import { useIsFocused, useNavigation } from '@react-navigation/native';

const QRCode = () => {
  const [hasPermission, setHasPermission] = useState<boolean>(null);
  const [scanned, setScanned] = useState<boolean>(false);
  const isFocused = useIsFocused();
  const linkTo = useLinkTo();
  const navigation = useNavigation();

  useEffect(() => {
    (async () => {
      const { status } = await BarCodeScanner.requestPermissionsAsync();
      setHasPermission(status === "granted");
    })();

    // 组件卸载时重置扫描状态
    return () => {
      setScanned(false);
    }
  }, []);

  // 页面失焦时主动重置扫描状态,避免下次进入无法扫描
  useEffect(() => {
    const unsubscribe = navigation.addListener('blur', () => {
      setScanned(false);
    });
    return unsubscribe;
  }, [navigation]);

  const handleBarCodeScanned = ({ type, data }: BarCodeEvent) => {
    setScanned(true);
    linkTo(data);
  };

  if (hasPermission === null) {
    return <Text>Requesting for camera permission</Text>;
  }

  if (hasPermission === false) {
    return <Text>No access to camera</Text>;
  }

  return (
    <View style={styles.container}>
      {/* 双重校验:仅页面聚焦时渲染扫描器 */}
      {isFocused ? (
        <BarCodeScanner
          onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
          style={StyleSheet.absoluteFill}
        />
      ) : null}
    </View>
  );
};
验证结果

修改完成后重新加载应用,从扫描页返回首页后1-2秒,系统状态栏的“Expo Go is using your camera”提示就会自动消失,相机资源被正常回收。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:09:18