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

扫码应用如何实现网络连接监听器?NetInfo使用遇异常触发问题

问题描述

我开发了一款可扫描二维码并从码中URL获取数据的应用。当用户失去网络连接时,应用会通过AsyncStorage存储这些URL。目前我需要实现一个监听器,在恢复网络连接时触发指定方法,请问有推荐的实现方式吗?

补充说明:我尝试使用NetInfo EventListener,但不确定是否使用有误,因为即使网络状态未改变,它也总是调用传入的函数。我的代码如下:

_connectionHandler = (e) => { 
  this.setState({ cameraActive: false }) 
  NetInfo.getConnectionInfo().then((connectionInfo) => { 
    if (connectionInfo.type === "none"){ 
      console.log("No internet") 
      dataArray.push(e.data) 
      let barcodeData_delta = { data: dataArray } 
      AsyncStorage.mergeItem(STORAGE_KEY, JSON.stringify(barcodeData_delta)); 
      NetInfo.isConnected.addEventListener( 
        'connectionChange', 
        this._handleConnectionChange(e.data) 
      ); 
      this.setState({ cameraActive: true }) 
    } else { 
      console.log("Internet available -> Going to read barcode now") 
      this._handleBarCodeRead(e.data); 
    } 
  }) 
}

解决方案

嘿,我一眼就看到你代码里的关键问题了——你在添加connectionChange监听器的时候,直接执行了this._handleConnectionChange(e.data),这会导致函数立刻被调用,而不是把函数本身作为监听回调传递进去。这就是为什么哪怕网络状态没变化,它也一直触发的原因。

下面我给你整理一套更合理的实现方案,解决这个问题的同时,也让代码结构更清晰:

1. 核心修正点

  • 监听器要在组件生命周期(比如componentDidMount)里统一添加,别在每次扫码的_connectionHandler里重复绑定,不然会导致同一个事件触发多次。
  • 添加监听器时要传函数引用(比如this.handleNetworkChange),而不是直接执行函数(this.handleNetworkChange())。

2. 完整代码示例

state = {
  cameraActive: true,
  pendingUrls: [] // 用来存离线时的待处理URL
}

componentDidMount() {
  // 组件加载时先从AsyncStorage读取之前存的待处理URL
  this.loadPendingUrls();
  
  // 绑定网络状态变化监听器
  NetInfo.isConnected.addEventListener(
    'connectionChange',
    this.handleNetworkChange
  );
}

componentWillUnmount() {
  // 组件卸载时一定要移除监听器,避免内存泄漏
  NetInfo.isConnected.removeEventListener(
    'connectionChange',
    this.handleNetworkChange
  );
}

// 读取存储的待处理URL
loadPendingUrls = async () => {
  try {
    const storedData = await AsyncStorage.getItem(STORAGE_KEY);
    if (storedData) {
      this.setState({ pendingUrls: JSON.parse(storedData).data || [] });
    }
  } catch (err) {
    console.error('读取待处理URL失败:', err);
  }
}

// 保存待处理URL到AsyncStorage
savePendingUrls = async (urls) => {
  try {
    await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify({ data: urls }));
  } catch (err) {
    console.error('保存待处理URL失败:', err);
  }
}

// 扫码后的处理逻辑
_connectionHandler = async (e) => {
  this.setState({ cameraActive: false });
  
  // 先检查当前网络状态
  const isConnected = await NetInfo.isConnected.fetch();
  
  if (!isConnected) {
    console.log("无网络,存储URL");
    const newPendingUrls = [...this.state.pendingUrls, e.data];
    this.setState({ pendingUrls: newPendingUrls });
    await this.savePendingUrls(newPendingUrls);
  } else {
    console.log("有网络,立即处理URL");
    await this._handleBarCodeRead(e.data);
  }
  
  this.setState({ cameraActive: true });
}

// 网络状态变化的回调
handleNetworkChange = async (isConnected) => {
  // 只有当网络恢复,且有待处理URL时才执行
  if (isConnected && this.state.pendingUrls.length > 0) {
    console.log("网络恢复,开始处理待处理URL");
    
    // 逐个处理每个待处理的URL
    for (const url of this.state.pendingUrls) {
      try {
        await this._handleBarCodeRead(url);
      } catch (err) {
        console.error(`处理URL ${url}失败:`, err);
        // 如果某个URL处理失败,可以选择保留它下次再试,或者根据需求处理
        continue;
      }
    }
    
    // 全部处理完成后,清空存储和状态
    this.setState({ pendingUrls: [] });
    await this.savePendingUrls([]);
  }
}

3. 额外注意事项

  • 异步操作要加await:AsyncStorage的读写都是异步的,一定要用async/await确保操作完成后再执行下一步,避免数据不一致。
  • 错误处理不能少:对存储和网络请求的错误进行捕获,这样遇到问题时能快速定位,也不会导致应用崩溃。
  • 避免重复绑定:重复添加监听器会导致同一事件触发多次,所以一定要在组件卸载时移除,且只在初始化时绑定一次。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:23:53