Removing items from normalized redux store
Asked Answered
R

1

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 ?

Revival answered 15/10, 2016 at 6:48 Comment(5)
Lodash has a nice function called omit that returns an object without the passed in key. You can do something like: omit(state.entities.exercises, 2). Does this help?Prostitute
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)Fervency
Possible duplicate of How do you add/remove to a redux store generated with normalizr?Carl
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.Naturalistic
You can use the spread operator to isolate the dropped key and then return the ...rest. Another approach is to use Immer as used by Redux Toolkit. But lodash omit as mentioned by @Andrey is probably the best.Ledeen
N
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.

Nationalism answered 26/7, 2018 at 9:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.