React组件与BleManager.js蓝牙扫描通信实现(类iOS代理/观察者模式)
实现类似iOS代理/观察者模式的蓝牙扫描回调逻辑
作为iOS开发者,你习惯用代理或者通知中心来处理这类跨组件的回调逻辑,其实在JavaScript + React的场景下,我们有几种非常贴合的实现方式,刚好能解决你把蓝牙扫描判断逻辑移到React组件的需求。下面我结合你的BleManager.js代码给出具体方案:
方案一:自定义观察者模式(类似iOS NotificationCenter)
这种方式最接近iOS的通知机制,我们可以在BleManager里维护一个观察者列表,每当扫描到设备时就通知所有注册的观察者,由React组件来决定是否停止扫描。
改造BleManager.js
class BleManager { constructor() { this.observers = []; // 存储观察者列表 this.currentScanHandler = null; // 保存扫描handler,用于停止扫描 } // 添加观察者 addObserver(observer) { this.observers.push(observer); } // 移除观察者(防止内存泄漏) removeObserver(observer) { this.observers = this.observers.filter(obs => obs !== observer); } // 通知所有观察者 notifyObservers(device) { this.observers.forEach(observer => observer.onDeviceFound(device)); } startLeScan = () => { return new Promise((resolve, reject) => { navigator.mozBluetooth.defaultAdapter.startLeScan([]) .then(handlerLE => { this.currentScanHandler = handlerLE; // 保存handler handlerLE.ondevicefound = (eventLE) => { const device = eventLE.device; // 通知所有观察者当前扫描到的设备 this.notifyObservers(device); }; }) .catch(e => { console.log(e); reject({ error: e }); }); }); } // 新增停止扫描的方法 stopLeScan() { if (this.currentScanHandler) { navigator.mozBluetooth.defaultAdapter.stopLeScan(this.currentScanHandler); this.currentScanHandler = null; } } } export default new BleManager(); // 导出单例,方便全局使用
在React组件中使用观察者
import React, { Component } from 'react'; import BleManager from './BleManager'; class BluetoothScanner extends Component { componentDidMount() { // 注册观察者 BleManager.addObserver(this); // 开始扫描 BleManager.startLeScan().catch(err => console.error(err)); } componentWillUnmount() { // 移除观察者,避免内存泄漏 BleManager.removeObserver(this); // 组件卸载时停止扫描 BleManager.stopLeScan(); } // 观察者回调方法,对应BleManager里的notifyObservers调用 onDeviceFound = (device) => { console.log('扫描到设备:', device.address, device.name); // 这里由组件判断是否为目标设备 if (device.address === "ed:ec:90:87:5d:86") { console.log('找到目标设备,停止扫描'); BleManager.stopLeScan(); // 这里可以做后续逻辑,比如连接设备 } } render() { return ( <div> <h2>蓝牙扫描中...</h2> </div> ); } } export default BluetoothScanner;
方案二:回调函数模式(类似iOS Block回调)
如果你的场景比较简单,不需要多个观察者,直接给startLeScan传一个回调函数更简洁,类似iOS里的completion block。
改造BleManager.js的startLeScan方法
startLeScan = (onDeviceFoundCallback) => { return new Promise((resolve, reject) => { navigator.mozBluetooth.defaultAdapter.startLeScan([]) .then(handlerLE => { handlerLE.ondevicefound = (eventLE) => { const device = eventLE.device; // 调用传入的回调函数,把设备和扫描handler传给组件 onDeviceFoundCallback(device, handlerLE); }; }) .catch(e => { console.log(e); reject({ error: e }); }); }); }
在React组件中使用回调
import React, { Component } from 'react'; import BleManager from './BleManager'; class BluetoothScanner extends Component { componentDidMount() { BleManager.startLeScan((device, handlerLE) => { console.log('扫描到设备:', device.address, device.name); if (device.address === "ed:ec:90:87:5d:86") { console.log('找到目标设备,停止扫描'); navigator.mozBluetooth.defaultAdapter.stopLeScan(handlerLE); // 后续逻辑,比如发起设备连接 } }).catch(err => console.error(err)); } componentWillUnmount() { // 若需要在组件卸载时强制停止扫描,可参考方案一在BleManager中实现全局stop方法 } render() { return <div>蓝牙扫描中...</div>; } } export default BluetoothScanner;
方案对比
- 观察者模式:适合多个组件需要监听蓝牙扫描结果的场景,扩展性强,和iOS的NotificationCenter逻辑完全对齐。
- 回调函数:适合单一组件监听的简单场景,代码更精简,类似iOS的block回调逻辑。
两种方案都能实现你想要的"由React组件判断目标设备并停止扫描"的需求,你可以根据自己的项目复杂度选择。
内容的提问来源于stack exchange,提问作者sree_iphonedev
相关产品推荐
相关产品推荐

