简体   繁体   中英

Trying to store object into AsyncStorage but it stores empty values

I am working on a running tracker app using react-native. I fetch user's location every 5 meters and then store their lat and long inside a route array. When the user ends the run I want to store the array with all the points inside AsyncStorage. the problem is that when it stores an empty array.

this is what it stores. I'm not sure why. Any help is appreciated.

Object {
  "route": Array [],
  "speed": 0,
  "totalDistance": 0,
}

My code

github link for full project. https://github.com/jasingh784/runningTrackerv2

import React, {useState, useEffect} from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
import * as Location from 'expo-location';
import { getDistance } from '../utils';
import Timer from './Timer';
import { storeRun } from '../utils';


export default function NewRun() {
  const [route, setRoute] = useState([]);
  const [errorMsg, setErrorMsg] = useState(null);
  const [speed, setSpeed] = useState(0);
  const [totalDistance, setTotalDistance] = useState(0);


  //setup watch position
  useEffect(() => {
    (async () => {
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('Permission to access location was denied');
        return;
      }

      locationSubscription = await Location.watchPositionAsync({accuracy: Location.Accuracy.BestForNavigation, distanceInterval: 5}, locationUpdated);
    })();

    return () => {
      endRun()
      locationSubscription.remove();
    }

  }, []);

  //this effect runs every time a new coord is added to the route array.
  //it calls a function to calculate the distance between two points. it then adds the 
  //result to the total distance. 
  useEffect(() => {
    if(route.length >= 2) {
      distBetweenLastPoints = getDistance(route[route.length - 1]["latitude"], 
                  route[route.length - 2]["latitude"],
                  route[route.length - 1]["longitude"],
                  route[route.length - 2]["longitude"] );
        
      setTotalDistance(totalDistance => totalDistance + distBetweenLastPoints)
    }
    return ()=> {
      //not sure if there is any clean up in this effect. i dont think so.
      
    }
  }, [route])


  //get location and add entry into the route array. This array contains points
  //that can be used to map out the route.
  const locationUpdated = (locObject) => {
    console.log('inside locationupdated')
    //console.log(locObject)

    setRoute(oldRoute => [...oldRoute, {
      latitude: locObject.coords.latitude,
      longitude: locObject.coords.longitude,
    }]);

    setSpeed(locObject.coords.speed);

  }

  //this function is called when user presses End Run.
  //it puts all the data for the run into one object and 
  //then stores it in local storage. it only stores the last run
  //also remves the location subscription so we app can stop tracking 
  //location
  const endRun = () => {
    const run = {route, totalDistance, speed}
    console.log(run)
    storeRun(run);
    locationSubscription.remove();
  }


  let text = 'Waiting..';
  if (errorMsg) {
    text = errorMsg;
  } else if (route) {
    text = JSON.stringify(route);
  }

  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>{Math.round((speed * 2.2369) * 100) / 100} mph</Text>
      <Text>Distance Travelled: {route ? totalDistance : 0} miles</Text>
      <Timer />
      <Button title="End Run" onPress={endRun}/>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    
    alignItems: 'center',
    justifyContent: 'center',
  },
});

code to storeRun

export const storeRun = async (runData) => {
        try {
          const jsonValue = JSON.stringify(runData)
          await AsyncStorage.setItem('previousRun', jsonValue)
        } catch (e) {
          // saving error
          console.log(e);
        }
        console.log('added previous run to local storage');
      }

You can try React.useRef to refer to the updated value of lat and long.

Because when you register the pubsub listener, the state value is always fixed inside of the event callback.

The code below is a simple example to use useRef to get the latest updated value of a State inside the event-callback or pubsub.

const [counter, setCounter] = React.useState(0); // this is the target

const counterRef = React.useRef(); // ref
counterRef.current = counter; // ref always refers to counter


// event callback
const func = () => {
  // This should NOT be "counter" itself. Should be "counterRef"
  console.log(counterRef.current);
};


// event listener or pubsub
React.useEffect(() => {
  window.addEventListener("click", func);
}, []);

return (
  <button onClick={() => setCounter(counter + 1)}>
    click me!
  </button>

ok. so I found a workaround to my problem. I made a new function and put the code to store items in there. then i made a button and called that function when button gets pressed. I'm not sure why the same code wont work in the clean up of my useffect hook. It could be that my component gets unmounted before the code finished to run??? I dont know enough about react yet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM