2 votes

"Synchrone" useState sans useEffect

J'ai une liste des périphériques Bluetooth détectés, deviceList qui est configuré avec useState :

const [deviceList, setDeviceList] = useState([]);

J'ai un bouton qui déclenche l'analyse des appareils. J'ai besoin que la liste des dispositifs soit réinitialisée à [] à chaque fois qu'un scan démarre. Je le fais :

const scanForDevices = () =>  {
    setDeviceList([]);

    manager.startDeviceScan(null, null, (error, device) => {
        // add device to device list
        setDeviceList(old => [...old, device]);
    }
}

Le problème est que setDeviceList n'est pas synchrone, et deviceList n'est pas réinitialisé au moment où le nouveau périphérique est censé être ajouté. Il peut en résulter des dispositifs en double. Je peux éviter les doublons en filtrant, mais ce n'est qu'une astuce pour résoudre le problème actuel.

Je ne peux pas utiliser useEffect pour résoudre ce problème, alors ne le suggérez pas. startDeviceScan ne peut pas être exécuté à chaque fois deviceList changements.

Comment des situations comme celle-ci sont-elles résolues en l'absence d'un système véritablement atomique ? setState ?

0voto

Ed Lucas Points 31

Si vous essayez d'effacer la liste et startDeviceScan renvoie plusieurs dispositifs, il semble que vous pourriez créer une variable temporaire pour construire la liste, puis définir l'état lorsque vous avez terminé.

const scanForDevices = () =>  {
    const devices = [];

    manager.startDeviceScan(null, null, (error, device) => {
        // add device to device list
        devices.push(device);
    }

    setDeviceList(devices);
}

0voto

Ed Lucas Points 31

Avez-vous essayé d'utiliser le useReducer crochet pour changer d'état ? Je n'ai pas essayé de résoudre un problème de timing comme le vôtre avec ce crochet, mais ça vaut le coup d'essayer.

La solution pourrait ressembler à ceci (non testé) :

const initialState = []
const reducer = (state, {type, payload}) => {
  switch (type) {
    case 'RESET':
      return initialState
    case 'ADD_DEVICE':
      return [...state, payload]
    default:
      return state
  }
}
const [deviceList, dispatch] = useReducer(reducer, initialState)

...

const scanForDevices = () =>  {
  dispatch({type: 'RESET'})

  manager.startDeviceScan(null, null, (error, device) => {
    // add device to device list
    dispatch({type: 'ADD_DEVICE', payload: device})
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X