I'm building my first application with React and Redux. I'm trying to delete an item from an array in my reducer using splice.
Here my state:
favourite: { recipes: [], wines: [], products: [] }
Here my action:
if (action.type === "REMOVE_RECIPE_FROM_FAV") {
let favourite = state.favourite;
favourite.recipes.splice(action.data, 1);
return {
...state,
favourite: favourite,
};
}
When i console.log favourite i can see that I'm deleting the item, but my ponent doesn't update.
Could you please help me?
I'm building my first application with React and Redux. I'm trying to delete an item from an array in my reducer using splice.
Here my state:
favourite: { recipes: [], wines: [], products: [] }
Here my action:
if (action.type === "REMOVE_RECIPE_FROM_FAV") {
let favourite = state.favourite;
favourite.recipes.splice(action.data, 1);
return {
...state,
favourite: favourite,
};
}
When i console.log favourite i can see that I'm deleting the item, but my ponent doesn't update.
Could you please help me?
Share Improve this question asked May 9, 2020 at 13:03 Davide Davide 772 silver badges4 bronze badges 4-
do you mind to show code where you are getting and using this
favourite
variable? – Uma Commented May 9, 2020 at 13:06 -
8
reducers must return new data, not merely mutate it.
splice
mutates. As far as Redux is concerned,favourite
has not changed, as the reference is still the same. – Robin Zigmond Commented May 9, 2020 at 13:08 - I agree with @RobinZigmond so you must spread into a new array, see my answer below. – Fasani Commented May 9, 2020 at 13:13
- Does this answer your question? Is this the correct way to delete an item using redux? – wentjun Commented May 9, 2020 at 13:20
3 Answers
Reset to default 3You have to take care of the immutibility of the redux
state. You need to make a copy of the recipes
array and change it and merge with the state without affecting the others.
if (action.type === "REMOVE_RECIPE_FROM_FAV") {
let favourite = state.favourite;
const cloneRecipes = [...favourite.recipes];
cloneRecipes.splice(action.data, 1);
return {
...state,
favourite: {
...state.favourite,
recipes: cloneRecipes
}
}
}
Note that, the [...favourite.recipes]
makes a shallow copy of the recipes
array. For a nested array, it does not help you.
I suggest you to use Immutability Helpers library instead. By using this library the same task could be done like:
if (action.type === "REMOVE_RECIPE_FROM_FAV") {
return update(state, {
favourite: {
recipes: {$splice: [[action.data, 1]]}
}
});
}
As Robin Zigmond said that you must return a new state from reducer not mutate it so instead use array.filter
to remove the action.data
from the favourite array.
let favourite = state.favourite;
// this return new items array removing action.data from it.
let newFavouriteArray = favourite.filter(item => item !== action.data)
return {
...state,
favourite: newFavouriteArray,
};
Your reducers should be pure functions, meaning that they should not mutate the state passed in.
However, here you are modifying the state, since the favourite
variable that you create does not contain a copy of the favourite object in your state, but just a reference to it. Therefore, when you use splice, you are actually modifying the original recipes
array, not creating a new one, so Redux is not able to detect that it has changed, since it's actually the same object!
To avoid this problem, you could do something like this:
if (action.type === "REMOVE_RECIPE_FROM_FAV") {
return {
...state,
favourite: {...favourite,
recipes: { state.favourite.recipes.slice(action.data, action.data + 1) }
}
};
}
I'm assuming that action.data
contains the index of the element to remove.