如何从网络蓝牙订阅回调更新React/Recoil状态数组



我是React和Recoil的新手,希望通过使用Web Bluetooth API实时收集的数据显示实时图表(使用D3(。

简而言之,在调用await myCharacteristic.startNotifications()myCharacteristic.addEventListener('characteristicvaluechanged', handleNotifications)之后,每次从蓝牙设备通知新值时,都会调用handleNotifications回调(参见本示例(。

我正在使用钩子,并试图从回调中修改反冲状态(这被简化到了极致,我希望它具有代表性(:

export const temperatureState = atom({
key: 'temperature',
default: 0
})
export function BluetoothControls() {
const setTemperature = useSetRecoilState(temperatureState);
const notify = async () => {
...
temperatureCharacteristic.addEventListener('characteristicvaluechanged', event => {
setTemperature(event.target.value.getInt16(0))
}
}
return <button onClick={nofity}/>Start notifications</button>
}

如果我想在应用程序的某个地方显示最新的值,这很好。然而,我感兴趣的是将最后几个(比方说10个(值保留在一个循环缓冲区中,以绘制D3图表。

我尝试了一些类似的东西

export const temperatureListState = atom({
key: 'temperature-list',
default: []
})
export function BluetoothControls() {
const [temperatureList, setTemperatureList] = useRecoilState(temperatureListState);
const notify = async () => {
...
temperatureCharacteristic.addEventListener('characteristicvaluechanged', event => {
let temperatureListCopy = temperatureList.map(x => x);
temperatureListCopy.push(event.target.value.getInt16(0))
if (temperatureListCopy.length > 10)
temperatureListCopy.shift()
setTemperatureList(temperatureListCopy)
}
}
return <button onClick={nofity}/>Start notifications</button>
}

然而,很明显,我遇到了这里描述的问题,其中函数使用的是在渲染过程中捕获的旧版本的temperatureList。结果,temperatureState总是空的,然后用一个元素的列表替换。

如何在从外部回调更新的React状态/Recoil原子中维护一致的列表?我认为这个问题有点类似,但我想避免使用另一个扩展,如雷科Nexus。

useSetRecoilState接受一个updater函数作为参数,将要更新的值作为第一个参数:

export function BluetoothControls() {
const setTemperatureList = useSetRecoilState(temperatureListState);
const notify = async () => {
...
temperatureCharacteristic.addEventListener('characteristicvaluechanged', event => {
setTemperatureList(t => {
let temperatureListCopy = t.map(x => x);
temperatureListCopy.push(event.target.value.getInt16(0))
if (temperatureListCopy.length > 10)
temperatureListCopy.shift()
return temperatureListCopy
})
}
}
return <button onClick={nofity}/>Start notifications</button>
}

这解决了问题,因为updater函数只在事件上求值。

相关内容

  • 没有找到相关文章

最新更新