react-native-ble-plx: Bug Report userState React Hooks

Expected Behavior

When using “const [devices, setDevices] = useState([])” or any statefunction inside the scaning from ‘startDeviceScan’ the event stops

Current Behavior

The event stop and no more devices are found

Context

[CoreBluetooth] API MISUSE: <CBCentralManager: 0x281ab8af0> has no restore identifier but the delegate implements the centralManager:willRestoreState: method. Restoring will not be supported 2020-01-19 20:06:06.293648+0100 Zipforce[23222:18432691] [CoreBluetooth] XPC connection invalid [RxBLEKit|DEBG|19:06:06.301]: CentralManager(10765437680) didUpdateState(state: poweredOn)

  • Library version: 1.1.1
  • Platform: OS.
  • Platform logs (XCode):
const bleManager = new BleManager();

    const [deviceScan, setDeviceScan] = useState(false)
    const [devices, setDevices] = useState([])

    const stopDeviceScan = () => {
        console.trace('stopDeviceScan')
        bleManager.stopDeviceScan()
        setDeviceScan(false)
    }

    const addDevice = (device) => {
        console.trace('addDevice')
        console.log(device.id, device.name, device.localName)
        if (device.isConnectable &&
            device.localName &&
            devices.findIndex((x) => x.id == device.id) === -1) {

            setDevices([...devices, {
                id: device.id,
                name: device.name,
                localName: device.localName,
                isConnectable: device.isConnectable,
                rssi: device.rssi
            }])
        }
    }

    const startDeviceScan = () => {
        console.trace('startDeviceScan')
        bleManager.startDeviceScan(null, { allowDuplicates: false }, (error, device) => {
            if (error) {
                console.error(error)
            } else {
                addDevice(device)
            }
        })
    }

    useEffect(() => {
        console.trace('Init - Timer')
        let timerId = setTimeout(() => {
            stopDeviceScan()
        }, 15000)
        return () => clearTimeout(timerId);
    }, [])

    useEffect(() => {
        console.trace('Init')
        setDevices([])
        setDeviceScan(true)
        const subscription = bleManager.onStateChange((state) => {
            switch (state) {
                case 'PoweredOn':
                    console.trace('PoweredOn')
                    subscription.remove();
                    startDeviceScan()
                    break;

                default:
                    break;
            }
        })
    }, [])

    useEffect(() =>{
        console.log('useEffect',devices)
    },[devices])

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 4
  • Comments: 26 (3 by maintainers)

Most upvoted comments

@Cierpliwy Could you explain why the BleManager cannot be instantiated inside the component?

Also, it would be extremely helpful to have an example react-native-ble-plx implementation using functional components. Do you know if this exists?

I’ve noticed the same thing when using monitorCharacteristicForService(). If I try to update state inside of my listener function, it only runs once and then stops.

Just to make things clear. You shouldn’t create BleManager inside the component. Is that true in your case?

I dont see that the scanning stops, but I do see that this:

  setDevices([...devices, {
                id: device.id,
                name: device.name,
                localName: device.localName,
                isConnectable: device.isConnectable,
                rssi: device.rssi
            }])

needs to be this :

  setDevices(prevDevices => [...prevDevices, {
                id: device.id,
                name: device.name,
                localName: device.localName,
                isConnectable: device.isConnectable,
                rssi: device.rssi
            }])

i believe the problem arrises from the state hook causing a re-render. i fixed it by useRef for the manager and useReducer, rather then useState for storing the devices i get back from the scan.

Yeah, example was prepared to be concise. In general I highly recommend to create clear separation between BLE logic and UI of your application.

@Cierpliwy Wow! Just tried it! Fixed my problem! Damn… that was really stupid of me!

I ve been trying to fix this for at least 2 Days now…

But how come this works inside a Class-Component:

import React, { Component } from 'react';
import { Platform, View, Text } from 'react-native';
import { BleManager } from 'react-native-ble-plx';

export default class SensorsComponent extends Component {

  constructor() {
    super()
    this.manager = new BleManager()
    this.state = {info: "", values: {}}
    this.prefixUUID = "f000aa"
    this.suffixUUID = "-0451-4000-b000-000000000000"
    this.sensors = {
      0: "Temperature",
      1: "Accelerometer",
      2: "Humidity",
      3: "Magnetometer",
      4: "Barometer",
      5: "Gyroscope"
    }
  }
.....

Taken from https://www.polidea.com/blog/ReactNative_and_Bluetooth_to_An_Other_level/

Yes, it is the same and it also works for me. I can’t reproduce the issue then…

@senner007 Thanks for the quick reply! But how exactly do you mean that? Outside of the Component?

Extract the search function and pass in a function to update the state