0

I'm having some trouble figuring out how to handle sensor data in React Native. My goal is to get phone sensor data for a limited time (let's say 10 seconds) and after completion save the list obtained to local database. However pushing new gyroscope value to state array is one option but getting maximum update depth exceeded error in there. The code is below.

import React from 'react';
import {
  StyleSheet,
  View,
  Text,
  Dimensions,
} from 'react-native';
import { Gyroscope } from 'expo-sensors';
import { Button } from "native-base";
import CountDown from 'react-native-countdown-component';
import UUID from 'pure-uuid';
import {insertGyroData} from './measureService';

const SAMPLING_RATE = 20; // defaults to 20ms

export class Measure extends React.Component {
  state = {
    gyroscopeData: {},
    measuringStarted: false,
    x_gyro: [0],
    y_gyro: [0],
    z_gyro: [0]
  };

  componentDidMount() {
    this.toggleGyroscope();
  }

  componentWillUnmount() {
    this.unsubscribeAccelerometer();
  }

  toggleGyroscope = () => {
    if (this.gyroscopeSubscription) {
      this.unsubscribeAccelerometer();
    } else {
      this.gyroscopeSubscribe();
    }
  };

  gyroscopeSubscribe = () => {
    Gyroscope.setUpdateInterval(20);
    this.gyroscopeSubscription = Gyroscope.addListener(gyroscopeData => {
      this.setState({ gyroscopeData });
    });
  };

  unsubscribeAccelerometer = () => {
    this.gyroscopeSubscription && this.gyroscopeSubscription.remove();
    this.gyroscopeSubscription = null;
  };

  referenceMeasurementCompleted = async (x, y, z) => {
    this.setState({ measuringStarted: false });
      const uuid = new UUID(4).format();
      await insertGyroData([uuid, 'admin', '12345', x.toString(), y.toString(), z.toString()]);
    alert('Reference measurements completed');
  };

  render() {
    let { x, y, z } = this.state.gyroscopeData;
    const { x_gyro, y_gyro, z_gyro } = this.state;
    if (this.state.measuringStarted) {
      this.setState(({ x_gyro: [...x_gyro, x], y_gyro: [...y_gyro, y], z_gyro: [...z_gyro, z] }));

      return (
        <View style={styles.container}>
          <Text>Gyroscope:</Text>
          <Text>
            x: {round(x)} y: {round(y)} z: {round(z)}
          </Text>
          <Text>Time spent:</Text>
          <CountDown
            until={5}
            size={30}
            onFinish={() => this.referenceMeasurementCompleted(x_gyro, y_gyro, z_gyro)}
            digitStyle={{ backgroundColor: '#FFF' }}
            digitTxtStyle={{ color: '#00c9ff' }}
            timeToShow={['M', 'S']}
            timeLabels={{ m: 'MM', s: 'SS' }}
          />
        </View>
      );
    } else {
      return (
        <View style={styles.container}>
          <Button
            rounded
            primary
            onPress={() => this.setState({ measuringStarted: true })}
          >
            <Text style={styles.buttonText}>Start reference measurements</Text>
          </Button>
        </View>
      );
    }
  }
}

function round(n) {
  if (!n) {
    return 0;
  }

  return Math.floor(n * 100) / 100;
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    height: Dimensions.get('window').height,
    backgroundColor: 'white',
    alignItems: 'center',
    justifyContent: 'center'
  },
  buttonText: {
    color: 'white',
    fontSize: 20,
    paddingHorizontal: 10,
  },
});

With the current solution I'm getting Maximum Depth Update Exceeded error Please help!

1 Answers1

1

The error is obviously coming from this block since you are changing state inside the render.

if (this.state.measuringStarted) {
  this.setState(({ x_gyro: [...x_gyro, x], y_gyro: [...y_gyro, y], z_gyro: [...z_gyro, z] }));

}

One way you can try is updating the state in

componentDidUpdate(prevProps,prevState){}

But take care that it does not lead to Maximum Stack Reached error. With proper conditional statements you can set the state to new data without infinite recursion.

Thakur Karthik
  • 3,034
  • 3
  • 15
  • 24