NgRx 添加一个对象到对象列表

NgRx add an object to the list of objects

我有一个具有以下结构的状态。它包含一个锻炼列表,每个锻炼都有一个与此锻炼相关的锻炼列表。 我希望能够做两件事:

  1. 从锻炼列表中向特定锻炼添加新锻炼
  2. 从特定锻炼中删除特定锻炼

例如在我的 UI 中,我可以将新练习添加到名为 Day 2 的锻炼中。 所以我的动作有效载荷有 2 个参数:锻炼索引(这样我可以稍后在状态中找到它)和应该从特定锻炼的锻炼列表中添加的锻炼 to/deleted。

state = {
 workouts: [
  {
    name: "Day 1",
    completed: false,
    exercises: [{
      name: "push-up",
      completed: false
    },
    {
      name: "running",
      completed: false
    }]
  },
  {
    name: "Day 2",
    completed: false,
    exercises: [{
      name: "push-up",
      completed: false
    }]
  },
  {
    name: "Day 3",
    completed: false,
    exercises: [{
      name: "running",
      completed: false
    }]
   }]
}

操作数

export class AddExercise implements Action {
  readonly type = ADD_EXERCISE
  constructor(public payload: {index: number, exercise: Exercise}) {}
}

export class DeleteExercise implements Action {
  readonly type = DELETE_EXERCISE
  constructor(public payload: {index: number, exercise: Exercise}) {}
}

而且我卡在减速器上了。你能建议应该如何正确完成吗? 这是现在的样子(尚未最终确定):

减速器

export function workoutsReducer(state = initialState, action: WorkoutActions.Actions) {
  switch(action.type) {
    case WorkoutActions.ADD_EXERCISE:
       const workout = state.workouts[action.payload.index];
       const updatedExercises = [
         ...workout.exercises,
         action.payload.exercise
       ]
       return {
         ...state,
          workouts: [...state.workouts, ]
       }
    return {};
    default:
      return state;
  }
}

谢谢!

请尝试如下操作(我在代码中加入了注释,希望它能说明问题):

export function workoutsReducer(state = initialState, action: WorkoutActions.Actions) {
  switch(action.type) {
    case WorkoutActions.ADD_EXERCISE:
       // You can take advantage of the fact that array map receives 
       // the index as the second argument
       // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
       const workouts = state.workouts.map((workout, index) => {
         if (index != action.payload.index) {
           return workout;
         }

         // If it is the affected workout, add the new exercise
         const exercises = [
           ...workout.exercises,
           action.payload.exercise
         ]

         return { ...workout, exercises }
       })
       
       // return the updated state
       return {
         ...state,
         workouts
       }

    case WorkoutActions.DELETE_EXERCISE:
       // very similar to the previous use case
       const workouts = state.workouts.map((workout, index) => {
         if (index != action.payload.index) {
           return workout;
         }

         // the new exercises array will be composed by every previous
         // exercise except the provided one. I compared by name, 
         // I don't know if it is accurate. Please, modify it as you need to
         const exercises = workout.exercises.filter((exercise) => exercise.name !== action.payload.exercise.name);

         return { ...workout, exercises }
       })
       
       // return the new state 
       return {
         ...state,
         workouts
       }

    default:
      return state;
  }
}