这是使用 redux 删除项目的正确方法吗?

我知道我不应该变异输入,应该克隆对象来变异它。我遵循了一个 redux 启动项目中使用的惯例,它使用:

ADD_ITEM: (state, action) => ({
...state,
items: [...state.items, action.payload.value],
lastUpdated: action.payload.date
})

用于添加一个项目-我得到了使用传播来追加数组中的项目。

删除我使用:

DELETE_ITEM: (state, action) => ({
...state,
items: [...state.items.splice(0, action.payload), ...state.items.splice(1)],
lastUpdated: Date.now()
})

但是这会使输入状态对象发生变化——即使我返回了一个新对象,这也是被禁止的吗?

133249 次浏览

不,永远不要变异你的状态。

即使返回一个新对象,仍然会污染旧对象,而这是您永远不想做的。这使得在比较旧状态和新状态时存在问题。例如在 shouldComponentUpdate中,反应还原在引擎盖下使用。它还使得时间旅行变得不可能(比如撤消和重做)。

相反,使用不可变的方法。始终使用 Array#slice而不是 Array#splice

我假设从您的代码中,action.payload是被删除项的索引。更好的办法如下:

items: [
...state.items.slice(0, action.payload),
...state.items.slice(action.payload + 1)
],

可以使用数组筛选器方法从数组中删除特定元素,而不必改变原始状态。

return state.filter(element => element !== action.payload);

在代码的上下文中,它看起来是这样的:

DELETE_ITEM: (state, action) => ({
...state,
items: state.items.filter(item => item !== action.payload),
lastUpdated: Date.now()
})

ES6Array.prototype.filter方法返回一个新数组,其中包含符合条件的项。因此,就原来的问题而言,这将是:

DELETE_ITEM: (state, action) => ({
...state,
items: state.items.filter(item => action.payload !== item),
lastUpdated: Date.now()
})

对于带有对象的数组,不可变的“ DELETED”减法器的另一个变体是:

const index = state.map(item => item.name).indexOf(action.name);
const stateTemp = [
...state.slice(0, index),
...state.slice(index + 1)
];
return stateTemp;

黄金法则是,我们不会返回一个变异的状态,而是一个新的状态。根据操作的类型,当状态树触及减速器时,可能需要以各种形式更新状态树。

在这个场景中,我们试图从状态属性中删除一个项。

这就引出了 Redux 的不可变更新(或数据修改)模式的概念。不可变性是关键,因为我们永远不想直接更改状态树中的值,而是总是复制并基于旧值返回新值。

下面是一个如何删除嵌套对象的示例:

// ducks/outfits (Parent)


// types
export const NAME = `@outfitsData`;
export const REMOVE_FILTER = `${NAME}/REMOVE_FILTER`;


// initialization
const initialState = {
isInitiallyLoaded: false,
outfits: ['Outfit.1', 'Outfit.2'],
filters: {
brand: [],
colour: [],
},
error: '',
};


// action creators
export function removeFilter({ field, index }) {
return {
type: REMOVE_FILTER,
field,
index,
};
}


export default function reducer(state = initialState, action = {}) {
sswitch (action.type) {
case REMOVE_FILTER:
return {
...state,
filters: {
...state.filters,
[action.field]: [...state.filters[action.field]]
.filter((x, index) => index !== action.index)
},
};
default:
return state;
}
}

为了更好地理解这一点,请务必查看这篇文章: https://medium.com/better-programming/deleting-an-item-in-a-nested-redux-state-3de0cb3943da

使用 redux 以不同方式删除项。

方法1: 在这种情况下使用 创建切片(. .)

const { id } = action.payload; // destruct id
removeCart: (state, action) =>{
let { id } = action.payload;
let arr = state.carts.filter(item => item.id !== parseInt(id))
state.carts = arr;
}

方法2: 在这种情况下使用 开关(...) ,扩展运算符

const { id } = action.payload; // destruct id


case actionTypes.DELETE_CART:
return {
...state,
carts: state.carts.filter((item) => item.id !== payload)
};

对于初始化此状态的两个方法:

  initialState: {
carts: ProductData, // in productData mocked somedata
}