web-dev-qa-db-ja.com

これは、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() 
})

しかし、これは入力状態オブジェクトを変化させています-新しいオブジェクトを返しているにもかかわらず、これは禁止されていますか?

92
CWright

いいえ。自分の状態を変更しないでください。

新しいオブジェクトを返している場合でも、古いオブジェクトを汚染しているため、決して実行したくありません。これにより、古い状態と新しい状態を比較するときに問題が生じます。たとえば、react-reduxが内部で使用するshouldComponentUpdateの場合。また、タイムトラベルが不可能になります(つまり、元に戻すとやり直し)。

代わりに、不変のメソッドを使用します。常にArray#sliceを使用し、Array#spliceを使用しないでください。

コードからaction.payloadが削除されるアイテムのインデックスであると仮定します。より良い方法は次のとおりです。

items: [
    ...state.items.slice(0, action.payload),
    ...state.items.slice(action.payload + 1)
],
166
David L. Walsh

配列フィルターメソッドを使用して、元の状態を変更せずに配列から特定の要素を削除できます。

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

コードのコンテキストでは、次のようになります。

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

ES6のArray.prototype.filterメソッドは、条件に一致するアイテムを含む新しい配列を返します。したがって、元の質問のコンテキストでは、これは次のようになります。

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

オブジェクトを含む配列の不変の「DELETED」レデューサーのもう1つのバリエーション:

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