React Native接收BLE数据时实时图表不显示问题排查
问题定位
你的图表完全不显示是4个代码逻辑错误共同导致的,没有玄学问题:
- 渲染逻辑写反:
initialState中isLoading默认值是false,render方法里写的是this.state.isLoading ? 渲染图表容器 : 返回null,等于组件加载完永远返回空节点,根本不会挂载Chart组件,这是最直接的不显示原因。 - BLE数据链路断了:你在
DeviceScreen里只完成了设备连接和服务发现,没有订阅对应BLE特征值的实时通知,也没有把收到的hr值作为属性传给ChartScreen,写的<ChartScreen chartdata />是无效空属性,ChartScreen里引用的全局hr不是响应式变量,值变了组件根本不会触发更新。 - 生命周期用错:
getDerivedStateFromProps的标准入参是(nextProps, prevState),你写的入参不对,而且每次触发都直接把flow覆盖为[hr]单元素数组,就算拿到了新值也存不下历史数据,不可能实现滚动实时曲线效果。 - 初始值引用风险:
initialState里直接引用未经过组件传入的hr,如果hr不是显式导入的全局常量,组件初始化就会抛出引用错误。
修复方案
1. 改造DeviceScreen,补全BLE特征订阅逻辑,把实时hr传给图表组件
你现在只拿到了设备服务列表,没有监听特征值变化,补上对应逻辑:
// 新增hr值的状态存储 const [hr, setHr] = useState<number>(0); useEffect(() => { const getDeviceInformations = async () => { // 连接设备 const connectedDevice = await device.connect(); setIsConnected(true); // 发现服务和特征 const allServicesAndCharacteristics = await connectedDevice.discoverAllServicesAndCharacteristics(); const discoveredServices = await allServicesAndCharacteristics.services(); setServices(discoveredServices); // 补全特征订阅逻辑,UUID替换成你自己设备对应的心率服务、特征UUID const hrService = await connectedDevice.getService("你的心率服务UUID"); const hrCharacteristic = await hrService.getCharacteristic("你的心率特征UUID"); // 监听特征值实时变化 hrCharacteristic.monitor((error, characteristic) => { if (error || !characteristic) return; // 按照硬件协议解析hr数值,以下为示例解析逻辑,替换成你设备对应的解析规则 const realTimeHr = characteristic.readUInt16(0) || 0; setHr(realTimeHr); }); // 原有权限申请逻辑保留 PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, { title: 'Permission Localisation Bluetooth', message: 'Requirement for Bluetooth', buttonNeutral: 'Later', buttonNegative: 'Cancel', buttonPositive: 'OK', } ); }; getDeviceInformations(); // 原有断开监听、卸载返回逻辑保留 device.onDisconnected(() => { navigation.navigate('Home'); }); return () => { disconnectDevice(); }; }, [device, disconnectDevice, navigation]); // 渲染部分把hr作为有效属性传给ChartScreen,删掉空的chartdata属性 <View> <ChartScreen hr={hr} /> </View>
2. 重写ChartScreen逻辑,删掉错误的生命周期方法
import React, { Component } from 'react'; import { Dimensions, StyleSheet, View, ActivityIndicator } from 'react-native'; // 自行导入你项目里的Chart、ScreenContainer组件 const width = Dimensions.get('window').width; const height = Math.floor((Dimensions.get('window').height - 150) / 3); const slotsPerWidth = 100; // 最多缓存100个数据点,满了就删除最旧的点实现滚动效果 const MAX_DATA_POINTS = 100; class ChartScreen extends Component { state = { flow: [], isLoading: true, }; // 监听传入的hr变化,追加到数据数组 componentDidUpdate(prevProps) { if (prevProps.hr !== this.props.hr && this.props.hr !== undefined) { this.setState(prevState => { const newFlow = [...prevState.flow, this.props.hr]; if (newFlow.length > MAX_DATA_POINTS) newFlow.shift(); return { flow: newFlow, isLoading: false } }) } } render() { const { flow } = this.state; // 加载中显示loading if (this.state.isLoading) { return ( <ScreenContainer> <View style={styles.main}> <ActivityIndicator size="large" color="#fff"/> </View> </ScreenContainer> ) } // 数据就绪渲染图表 return ( <ScreenContainer> <View style={styles.main}> <Chart key="flow" data={flow} maxValue={1900} minValue={1750} slotsPerWidth={slotsPerWidth} width={width} height={height} marginBottom={20} lineColor="rgba(95, 92, 1, 1)" lineThickness={2} chartBackground="#17204d" horizontalGridLinesCount={5} gridColor="rgba(65, 95, 93, .4)" gridThickness={1} unit="ml" axisTooClose={10} labelsColor="rgba(255, 255, 255, 0.8)" labelsFontSize={12} marginLeft={60} labelsMarginLeft={15} /> </View> </ScreenContainer> ) } } const styles = StyleSheet.create({ main: { flex: 1, alignItems: 'center', justifyContent: 'center' }, }); export default ChartScreen;
额外检查项
- 确认你用的Chart组件的
data入参要求:如果要求传入带x/y坐标的对象数组,需要在追加数据时补上x轴序号。 - BLE特征值解析逻辑必须和硬件厂商给出的协议对齐,如果解析出的数值超出你设置的
minValue/maxValue范围,图表也不会正常画线。 - 安卓12及以上版本需要额外申请
BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限,否则会出现低版本能收数据、高版本收不到的问题。
内容的提问来源于stack exchange,提问作者cans
相关产品推荐
相关产品推荐

