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

React Native中BottomSheet的useRef如何避免为null?扫码触发弹窗问题

解决扫码后BottomSheet引用为null及无法再次扫码的问题

问题根源

  1. BottomSheet引用为null:你的代码中BottomSheet仅在scanned为true时才渲染,扫码后调用setScanned(true)触发组件重渲染,但BottomSheet此时还未完成挂载,直接调用sheetRef.current.snapTo(0)自然拿不到实例。即使使用useEffect监听product或scanned状态,也可能因为组件渲染周期的问题,在ref赋值前就执行了回调。
  2. 无法再次扫码:scanned设为true后,BarCodeScanner的onBarCodeScanned被设为undefined,扫码器直接失效,且没有重置scanned的逻辑,导致无法再次扫码。

修正方案

  • 让BottomSheet始终挂载在DOM中,通过index属性控制显示/隐藏(index=-1为关闭状态),确保sheetRef始终能获取到实例。
  • 在BottomSheet关闭时(比如用户下滑关闭),重置scanned状态,恢复扫码器的功能。
  • 扫码成功后直接调用snapTo(0)展开BottomSheet,无需等待状态更新后的副作用。

修改后的完整代码

const ScanScreen = ({ navigation }) => {
  const width = Dimensions.get("window").width;
  const height = Dimensions.get("window").height;

  const sheetRef = useRef(null);

  const [scanned, setScanned] = useState(false);
  const [product, setProduct] = useState({ name: "" });

  // 渲染BottomSheet内容,避免组件重复创建函数
  const renderProductModal = () => (
    <View style={{ height: 450 }}>
      <Text>Product: {product.name}. Swipe down to close.</Text>
    </View>
  );

  const handleScannedCodeBar = async ({ type, data }) => {
    if (!data) return;
    
    setProduct({ name: "Mon produit scanné" });
    // 直接调用snapTo,BottomSheet已常驻挂载,ref不为null
    sheetRef.current?.snapTo(0);
    // 临时禁用扫码,避免重复触发
    setScanned(true);
  };

  // BottomSheet关闭时重置扫码状态
  const handleSheetClose = () => {
    setScanned(false);
  };

  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      <BarCodeScanner
        onBarCodeScanned={scanned ? undefined : handleScannedCodeBar}
        style={{ height: height, width: width }}
      />
      {/* 始终渲染BottomSheet,用index控制显示 */}
      <SafeAreaView>
        <BottomSheet
          ref={sheetRef}
          index={-1} // 默认关闭
          snapPoints={[450, 300, 0]}
          borderRadius={10}
          renderContent={renderProductModal}
          // 监听BottomSheet关闭完成事件
          onCloseEnd={handleSheetClose}
        />
      </SafeAreaView>
    </View>
  );
};

export default ScanScreen;

关键修改说明

  1. BottomSheet常驻渲染:移除{scanned && ...}的条件渲染,让BottomSheet始终存在,确保sheetRef能稳定获取组件实例。
  2. 扫码逻辑调整:扫码成功后先设置产品数据,再调用snapTo(0)展开BottomSheet,最后设置scanned=true临时禁用扫码。
  3. 重置扫码状态:通过onCloseEnd监听BottomSheet关闭事件,在关闭完成时将scanned设为false,恢复扫码器功能。
  4. 性能优化:将productModal改为renderProductModal并移到状态定义下方,避免组件每次渲染都重新创建函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 02:20:28