Home > Software engineering >  Why is React Native AsyncStorage not updating state on mount?
Why is React Native AsyncStorage not updating state on mount?

Time:07-19

When I try to load the state from AsyncStorage for the screen I just navigated to, I am getting this error: TypeError: undefined is not an object (evaluating 'weights[numExercise].map') It is trying to use the initial state that the screen initializes the state with, but I want the state to be loaded with the data that I specifically try to load it with on mount, within my useEffect hook.

const WorkoutScreen = ({ navigation, route }) => {
  const [workoutName, setWorkoutName] = useState("");
  const [exercisesArr, setExercisesArr] = useState([""]);
  // Each array inside the arrays (weights & reps), represents an exercise's sets.
  const [weights, setWeights] = useState([[""]]);
  const [reps, setReps] = useState([[""]]);
  const [restTimers, setRestTimers] = useState([""]);

useEffect(() => {
    try {
      console.log("loading workoutscreen data for:", route.params.name);
      const unparsedWorkoutData = await AsyncStorage.getItem(route.params.name);

      if (unparsedWorkoutData !== null) {
        // We have data!
        const workoutData = JSON.parse(unparsedWorkoutData);

        setWorkoutName(route.params.name.toString());
        setExercisesArr(workoutData[0]);
        setWeights(workoutData[1]);
        setReps(workoutData[2]);
        setRestTimers(workoutData[3]);
      }
    } catch (error) {
      // Error retrieving data
      console.log("ERROR LOADING DATA:", error);
    }
  }, []);

Then further down the line in a component it realizes the error because, again, it's using the initialized state for the weights state.

  Return (
     {weights[numExercise].map((weight, i) => {
        return (
          <SetComponent
            key={i}
            numSet={i}
            numExercise={numExercise}
            prevWeights={prevWeights}
            weights={weights}
            setWeights={setWeights}
            prevReps={prevReps}
            reps={reps}
            setReps={setReps}
            isDoneArr={isDoneArr}
            setIsDoneArr={setIsDoneArr}
          />
        );
      })}
  );

I've made sure that the data is being stored, loaded, and used correctly, so (I think) I've narrowed it down to be something asynchronous; whether it's the setting of the state or loading from storage, I don't know and I can't find a solution. I am new to React Native and would love some suggestions, thank you!

CodePudding user response:

It turns out that using multiple states was causing an issue, I'm assuming because it's asynchronous. So instead I used one state that held an object of states, like so:

const [states, setStates] = useState({
    workoutName: "",
    exercisesArr: [""],
    weights: [[""]],
    reps: [[""]],
    restTimers: [""],
    isDoneArr: [[false]],
    originalWorkoutName: "",
  });

The data was loaded as such:

  const loadWorkoutData = async () => {
    try {
      console.log("loading workoutscreen data for:", route.params.name);
      const unparsedWorkoutData = await AsyncStorage.getItem(route.params.name);

      if (unparsedWorkoutData !== null) {
        // We have data!
        const workoutData = JSON.parse(unparsedWorkoutData);

        setStates({
          workoutName: route.params.name,
          exercisesArr: workoutData[0],
          weights: workoutData[1],
          reps: workoutData[2],
          restTimers: workoutData[3],
          isDoneArr: workoutData[4],
          originalWorkoutName: route.params.name,
        });
      }
    } catch (error) {
      // Error retrieving data
      console.log("ERROR LOADING DATA:", error);
    }
  };
  • Related