これはreduxを使用してアイテムを削除する正しい方法ですか?


116

入力を変更することは想定されていないため、オブジェクトを複製して変更する必要があります。私は以下を使用する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() 
})

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


1
簡単な質問。Spliceは、削除したアイテムを返します。それはあなたの意図ですか?そうでない場合は、スライスを使用する必要があります。これは、突然変異禁止法にも準拠しています。
m0meni 2016年

この例では、配列の2つのセクションを新しい配列にスプライスして、削除したい項目を省略しています。スライスも削除されたアイテムを返しますよね?元の配列を変更せずにそれだけを行うので、それがより良いアプローチでしょうか?
CWright 2016年

@ AR7あなたの提案に従って: items: [...state.items.slice(0, action.payload.value), ...state.items.slice(action.payload.value + 1 )]入力を変更しないようにスプライスの代わりに今すぐスライスを使用-これは行く方法ですか、それとももっと簡潔な方法がありますか?
CWright 2016年

回答:


206

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

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

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

私はあなたのコードからそれaction.payloadが削除されているアイテムのインデックスであると思います。より良い方法は次のとおりです:

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

これは、配列の最後の要素を処理している場合は機能しません。また...、2番目のステートメントでを使用すると、状態のコンテンツが2倍になります
Thaenor

4
jsfiddle / codepenの例でそれを証明してください。のarr.slice(arr.length)内容に関係なく、スニペットは常に空の配列を生成する必要がありarrます。
デビッドL.ウォルシュ

1
@ david-l-walsh混乱して申し訳ありません。この例をテストするときには、タイプミスか何かを作成したに違いありません。それは不思議に働きます。私の唯一の質問は次のとおりです。なぜ...第2部でスプレッドオペレーターが必要なのか...state.items.slice(action.payload + 1)
テナー

5
Array#slice配列を返します。2つのスライスを1つの配列に結合するために、spread演算子を使用しました。それがないと、配列の配列ができます。
デビッドL.ウォルシュ

4
それは理にかなっている。明確にしていただきありがとうございます(最初は混乱してしまい申し訳ありませんでした)。
タエノール2017

149

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

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

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

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

1
フィルターは新しい配列を生成しますか?
chenop 2017年

6
@chenopはい、Array.filterメソッドは新しい配列を返します。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
ステフM

4
重複がある場合は、すべて削除されます。フィルターを使用して特定のインデックスを削除するには、たとえばarr.filter((val, i) => i !== action.payload )
erich2k8を

21

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

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

.filter()はES2015メソッドではありませんが、以前のバージョンのES5で追加されました。
morkro 2017年

7

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

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

0

黄金律は、変異した状態ではなく、新しい状態を返すことです。アクションのタイプによっては、レデューサーに到達したときに状態ツリーをさまざまな形式で更新する必要がある場合があります。

このシナリオでは、状態プロパティからアイテムを削除しようとしています。

これにより、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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.