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

IT技术 javascript reactjs redux
2021-02-11 14:39:39

我知道我不应该改变输入,应该克隆对象来改变它。我正在遵循 redux 入门项目中使用的约定:

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

添加项目 - 我使用 spread 将项目附加到数组中。

删除我用过:

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

但这正在改变输入状态对象 - 即使我正在返回一个新对象,这是否被禁止?

6个回答

不。永远不要改变你的状态。

即使您返回了一个新对象,您仍然在污染旧对象,这是您永远不想做的。这使得在旧状态和新状态之间进行比较时会出现问题。例如shouldComponentUpdate,react-redux 在幕后使用。它还使时间旅行变得不可能(即撤消和重做)。

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

我从您的代码中假设这action.payload是要删除的项目的索引。更好的方法如下:

items: [
    ...state.items.slice(0, action.payload),
    ...state.items.slice(action.payload + 1)
],
这就说得通了。非常感谢您的澄清(并为最初的困惑感到抱歉)。
2021-03-22 14:39:39
请用 jsfiddle/codepen 示例证明这一点。该片段arr.slice(arr.length)应始终产生一个空数组不管是什么内容arr
2021-03-31 14:39:39
如果我们正在处理数组中的最后一个元素,这将不起作用,而且...在第二个语句中使用 将使您的状态内容加倍
2021-04-04 14:39:39
@david-l-walsh 很抱歉造成混乱,我在测试这个例子时一定是打错字了。它创造奇迹。我唯一的问题是:为什么...在第二部分需要传播运算符-...state.items.slice(action.payload + 1)
2021-04-04 14:39:39
Array#slice返回一个数组。为了将两个切片组合成一个数组,我使用了扩展运算符。没有它,您将拥有一个数组数组。
2021-04-10 14:39:39

您可以使用数组过滤器方法从数组中删除特定元素而不改变原始状态。

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

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

DELETE_ITEM: (state, action) => ({
  ...state,
  items: state.items.filter(item => item !== action.payload),
  lastUpdated: Date.now() 
})
过滤器是否产生一个新数组?
2021-03-24 14:39:39
@chenop 是的, Array.filter 方法返回一个新数组。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
2021-04-03 14:39:39
请注意,如果有重复项,这将删除所有重复项。要使用过滤器删除特定索引,您可以使用例如arr.filter((val, i) => i !== action.payload )
2021-04-14 14:39:39

ES6Array.prototype.filter方法返回一个包含符合条件的项目的新数组。因此,在原始问题的上下文中,这将是:

DELETE_ITEM: (state, action) => ({
  ...state,
  items: state.items.filter(item => action.payload !== item),
  lastUpdated: Date.now() 
})
.filter() 不是 ES2015 的方法,而是在之前的 ES5 版本中添加的。
2021-03-27 14:39:39

具有对象的数组的不可变“DELETED”reducer 的另一种变体:

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