11

Please see this question first here. I am using this sample object that everyone has been using.

{
  entities: {
      plans: {
        1: {title: 'A', exercises: [1, 2, 3]},
        2: {title: 'B', exercises: [5, 6]}
      },
      exercises: {
        1: {title: 'exe1'},
        2: {title: 'exe2'},
        3: {title: 'exe3'}
        5: {title: 'exe5'}
        6: {title: 'exe6'}
     }
   },
currentPlans: [1, 2]
}

When the user clicks on "Remove Exercise", the message might look something like this:

{type: "REMOVE_EXERCISE", payload: 2}

Do I need to iterate over all plans, and then all exercises within each plan in order to remove this item ? How would this be done in the reducer ?

Community
  • 1
  • 1
tito
  • 149
  • 3
  • 10
  • 4
    Lodash has a nice function called [omit](https://lodash.com/docs/4.17.4#omit) that returns an object without the passed in key. You can do something like: `omit(state.entities.exercises, 2)`. Does this help? – Andrey Luiz Jun 15 '17 at 17:11
  • 2
    To removed from each `plan.exercises`, you can use the `Array.filter` function to keep all ids except the one that was removed, something like: `plan.exercises.filter(id => id!==2)` – strider Nov 12 '17 at 18:12
  • 2
    Possible duplicate of [How do you add/remove to a redux store generated with normalizr?](https://stackoverflow.com/questions/34954726/how-do-you-add-remove-to-a-redux-store-generated-with-normalizr) – Tomasz Mularczyk May 15 '18 at 11:36
  • 2
    The relation between plans and exercises is not a many-to-many right? So when you send the "REMOVE_EXERCISE" message you should know which plan the exercises belongs to. Just send the plan id with the message and you don't have to iterate over all plans. – Johannes May 30 '18 at 11:24
  • You can use the [spread operator](https://stackoverflow.com/a/40699412/10431574) to isolate the dropped key and then return the ...rest. Another approach is to use [Immer](https://immerjs.github.io/immer/docs/update-patterns) as used by Redux Toolkit. But lodash omit as mentioned by @Andrey is probably the best. – Linda Paiste Nov 08 '20 at 17:49

1 Answers1

0

Option A

Just delete the exercise and modify code that is handling plans to work with undefined objects too (this can be handy either way). Example of reducer:

[REMOVE_EXERCISE]: (state, action) => {
  const newState = {
    ...state  
  }
  delete newState.entities.exercises[action.payload] // deletes property with key 2
  return newState;
}

Option B

Delete exercise and pass through all plans to delete the refernce too. Example:

[REMOVE_EXERCISE]: (state, action) => {
  const newState = {
    ...state,
  };

  Object.keys(newState.entities.plans).map(planKey => {
    const currentPlan = newState.entities.plans[planKey];

    // Filters exercises array in single plan
    currentPlan.exercises = currentPlan.exercises.filter(exercise => {
      return exercise !== action.payload;
    });
    newState.entities.plans[planKey] = currentPlan;
  });

  delete newState.entities.exercises[action.payload];
  return newState;
},

Picking the right option depends on size of plans - when it will grow to significant size it could slow down this processing. In this case you can set-up speed tests on this part of code, implement Option B and see if/when it will be bottleneck.

Either way, I would update code that is consuming plans data to handle undefined value in exercises. This can be easily done in selectors.

CorwinCZ
  • 452
  • 1
  • 3
  • 13