0
const state = [
    {
        list: []
    }
];

The list is a list of student objects, for example:

list: [
   { id: 1, name: "Mark", attendance: true },
   { id: 2, name: "John", attendance: false }
]

I have a button that triggers a post request to an API to change attendance to true. Post request returns the student object that was changed as in e.g.:

{ id: 2, name: "John", attendance: true }

This works fine and if no errors, will dispatch ATTENDANCE_SUCCESS.

Now, with this kind of set-up:

export function students(state, action) {
    let latestState = state[state.length - 1],
        newState = Object.assign({}, latestState);
    switch (action.type) {
       case "ATTENDANCE_SUCCESS":
          if (action.res.errorCode == 0) {
             // Need to change redux state 'attendance' value to true for a student with ID returned from the POST request
          }
    }

Initially, I did:

const studentChanged = newState.list.find(function(student) {
  return (
        student.id ===
        action.res.data.id
  );
});
studentChanged.attendance = true;

But it mutates the state in the redux store (although I am not sure how it's exactly happening since I assumed newState is already a copy).

What's the proper way?

1

1 Answer 1

3

The following would update a single item in the array. The critical aspect here is that if the id of the item does not match the id from the action payload, it returns the item unaltered, otherwise it updates the attendance property. Array.prototype.map returns a new array so it would be immutable.

export function students(state, action) {
  switch (action.type) {
    case "ATTENDANCE_SUCCESS":
      if (action.res.errorCode == 0) {
        return state.map(student => {
          // we want to leave non matching items unaltered
          if (student.id !== action.res.data.id) {
            return student;
          }

          return { ...student, attendance: true };
        });
      }

      return state;          
    default:
      return state;
  }
}

Here is a StackBlitz to demonstrate the functionality.

Hopefully that helps!

Sign up to request clarification or add additional context in comments.

2 Comments

What does { ...student, attendance: true } do? It's as if it's copying the entire student object but just changing attendance property to a different value?
Correct, It's the Object Spread Operator. It's effectively Object.assign(), just more succinct. Copy all enumerable properties, then additional argument values, in this case the property attendance, get merged into that newly created object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.