Home > Software engineering >  What is causing a "Delay" in updating state in Redux?
What is causing a "Delay" in updating state in Redux?

Time:12-19

I'm struggling to understand what I'm doing wrong with the below Redux & React native code.

I'm trying to create a workout tracking app where a user can input their workout progress. I've created a 'workoutSessionSlice' to keep track of the state.

const initialState: IWorkoutSessionState = {
  currentTrackingEquipment: {
    createdOn: { seconds: 0, nanoseconds: 0 },
    equipmentName: '',
    repetitions: [],
    results: [],
    repetitionIndex: 0,
  },
  hasRunningSession: false,
  isTrackingEquipment: false,
  savedSessionEquipmentRecords: [],
};

export const workoutSessionSlice = createSlice({
  name: 'workoutSession',
  initialState,
  reducers: {
    saveEquipmentRecord: (
      state: any,
      action: PayloadAction<IEquipmentRecord>,
    ) => {
      state.savedSessionEquipmentRecords.push(action.payload);
    },
    addResult: (state: any, action: PayloadAction<IRepResult>) => {
      state.currentTrackingEquipment.results[
        state.currentTrackingEquipment.repetitionIndex
      ] = action.payload;
    },
    updateRepIndex: (state: any, action: PayloadAction<number>) => {
      state.currentTrackingEquipment.repetitionIndex = action.payload;
    },
  },
});

The user uses a certain piece of equipment and adds the result of each repetition to the state via a button. I've noticed that there is a 'delay' on the state as I console.log the payload and the state in the function of this button:

const handleAddRep = (success: boolean, nextRepIndex: boolean) => {

    console.log({
      repetitions:
        workOutSession.currentTrackingEquipment.results[
          workOutSession.currentTrackingEquipment.repetitionIndex
        ].repetitions,
      weight: equipmentTracking.wheelPickerValue,
      success,
    });

    dispatch(
      addResult({
        repetitions:
          workOutSession.currentTrackingEquipment.results[
            workOutSession.currentTrackingEquipment.repetitionIndex
          ].repetitions,
        weight: equipmentTracking.wheelPickerValue,
        success,
      }),
    );

    console.log(workOutSession);
  };

console:

Object {
  "repetitions": 15,
  "success": true,
  "weight": 100,
}

Object {
  "currentTrackingEquipment": Object {
    "createdOn": Object {
      "nanoseconds": 735000000,
      "seconds": 1671364848,
    },
    "equipmentName": "Bench-press-incline",
    "repetitionIndex": 0,
    "repetitions": Array [
      15,
      12,
      7,
    ],
    "results": Array [
      Object {                  // expected this object to be replaced
        "repetitions": 15,
        "success": false,
        "weight": 0,
      },
      Object {
        "repetitions": 12,
        "success": false,
        "weight": 0,
      },
      Object {
        "repetitions": 7,
        "success": false,
        "weight": 0,
      },
    ],
  },
  "hasRunningSession": true,
  "isTrackingEquipment": true,
  "savedSessionEquipmentRecords": Array [],
}

When I log the state manually outside of the function of the button, I do see the correct data in the array & object:

Object {
  "currentTrackingEquipment": Object {
    "createdOn": Object {
      "nanoseconds": 735000000,
      "seconds": 1671364848,
    },
    "equipmentName": "Bench-press-incline",
    "repetitionIndex": 1,
    "repetitions": Array [
      15,
      12,
      7,
    ],
    "results": Array [
      Object {
        "repetitions": 15,
        "success": true,
        "weight": 100,
      },
      Object {
        "repetitions": 12,
        "success": false,
        "weight": 0,
      },
      Object {
        "repetitions": 7,
        "success": false,
        "weight": 0,
      },
    ],
  },
  "hasRunningSession": true,
  "isTrackingEquipment": true,
  "savedSessionEquipmentRecords": Array [],
}

The problem is that this 'delay' also happens when I want save the record, resulting in the last object in the results array to not be updated.

onPress={() => {
  Alert.alert('Successfully finished rep?', undefined, [
    {
      text: 'Yes',
      onPress: () => {
        if (
          workOutSession.currentTrackingEquipment
            .repetitionIndex ===
          workOutSession.currentTrackingEquipment.results.length - 1
        ) {
          handleAddRep(true, false);  // Should update rep in "currentTrackingEquipment"
          Alert.alert('Finished tracking equipment?', undefined, [
            {
              text: 'Yes',
              onPress: () => {
                handleFinishEquipmentTracking(); // adds current tracking equipment to "savedSessionEquipmentRecords"
              },
            },
            {
              text: 'No, go back',
            },
          ]);
        } else {
          handleAddRep(true, true);
        }
      },
    },
  ]);
}}

I've tried setting the values at the object keys instead of replacing the entire object, but that didn't work as well. Any help will be appreciated!

I've tried setting the values at the object keys instead of replacing the entire object, but that didn't work as well. Any help will be appreciated!

CodePudding user response:

There is no "delay" - you are looking at old ("stale") data that will never get updated.

See this example:

let state = { foo: 1 }
const s = state
state = { foo: 2 }
// s is now { foo: 1 } and state is { foo: 2 }

Just because your state updates to a new value (and it will be a completely new object, since state updates are immutable) doesn't mean your local variables will update - they will still point at the same value they did before.

In the future, that component will rerender - and then const something = useSelector(...) will re-execute. And then you have a new variable with that same name and that new variable will have the new value (but soon again, run stale).

  • Related