扫码应用如何实现网络连接监听器?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
相关产品推荐
相关产品推荐

