2016-01-03 14 views
48

So che non dovrei mutare l'input e dovrei clonare l'oggetto per mutarlo. Stavo seguendo la convenzione utilizzata su un progetto redux di avviamento che ha usato:È questo il modo corretto di cancellare un oggetto usando redux?

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

per l'aggiunta di una voce - ho l'uso di diffusione per aggiungere l'elemento della matrice.

per la cancellazione ho usato:

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

ma questo sta mutando l'oggetto stato di input - è questo vietato anche se sto tornando un nuovo oggetto?

+1

domanda veloce. Splice restituisce gli oggetti che hai rimosso. È questa la tua intenzione? Se no dovresti usare slice, che si attiene anche alla legge sulle mutazioni. – m0meni

+0

Bene in questo esempio sto unendo le due sezioni dell'array in un nuovo array - con l'elemento che volevo rimuovere lasciato fuori. Slice restituisce anche l'elemento rimosso giusto? Solo lo fa senza mutare la matrice originale in modo che sarebbe l'approccio migliore? – Carlo

+0

@ AR7 come da suggerimento: 'articoli: [... state.items.slice (0, action.payload.value), ... state.items.slice (action.payload.value + 1)]' ora usa slice invece di splicing in modo da non mutare l'input - è questa la strada da percorrere o c'è un modo più conciso? – Carlo

risposta

99

No. Non muta mai il tuo stato.

Anche se stai restituendo un nuovo oggetto, stai ancora inquinando il vecchio oggetto, che non vorresti mai fare. Ciò rende problematico il confronto tra il vecchio e il nuovo stato. Ad esempio in shouldComponentUpdate che reagiscono-ridondano gli usi sotto il cofano. Rende anche impossibile viaggiare nel tempo (ad esempio, annullare e ripetere).

Invece, utilizzare metodi immutabili. Utilizzare sempre Array#slice e mai Array#splice.

Presumo dal codice che action.payload è l'indice dell'articolo rimosso. Un modo migliore sarebbe come segue:

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

questo non funziona se abbiamo a che fare con l'ultimo elemento dell'array, anche l'uso di '...' nella seconda istruzione raddoppierà il contenuto del tuo stato – Thaenor

+2

Provalo con un esempio jsfiddle/codepen. Il frammento 'arr.slice (arr.length)' dovrebbe sempre produrre una matrice vuota indipendentemente dal contenuto di 'arr'. –

+1

@ david-l-walsh scusa per la confusione, devo aver fatto un refuso o qualcosa durante il test di questo esempio. Funziona a meraviglia. La mia unica domanda è: perché la necessità dell'operatore di spread '...' nella seconda parte - '... state.items.slice (action.payload + 1)' – Thaenor

32

È possibile utilizzare il metodo del filtro matrice per rimuovere un elemento specifico da un array senza mutare lo stato originale.

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

Nel contesto del codice, sarebbe simile a questa:

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

Puoi scrivere questo nel contesto della domanda originale, cioè il richiedente ha una matrice di elementi all'interno dello stato, mentre la tua risposta suggerisce che lo stato è puramente la matrice stessa. – JoeTidee

+0

Il filtro produce un nuovo array? – chenop

+2

@chenop Sì, il metodo Array.filter restituisce un nuovo array. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter –

6

Il metodo ES6 Array.prototype.filter restituisce un nuovo array con gli elementi che corrispondono ai criteri. Pertanto, nel contesto della domanda originale, questo sarebbe:

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

'.filter()' non è un metodo ES2015, ma è stato aggiunto nella versione precedente ES5. – morkro

Problemi correlati