ohne

2016-02-12 11 views
9
Zustand mutiert mit einem anderen Array-Element ersetzen

Dies ist, wie zB von meinem Zustand aussieht:ohne

const INITIAL_STATE = { 
contents: [ {}, {}, {}, etc.. ], 
meta: {} 
} 

Ich brauche ein Element innerhalb Inhalts Array zu wissen, seinen Index zu können und irgendwie ersetzen, habe ich versucht:

 return { 
     ...state, 
     contents: [ 
      ...state.contents[action.meta.index], 
      { 
      content_type: 7, 
      content_body: { 
       album_artwork_url: action.payload.data.album.images[1].url, 
       preview_url: action.payload.data.preview_url, 
       title: action.payload.data.name, 
       subtitle: action.payload.data.artists[0].name, 
       spotify_link: action.payload.data.external_urls.spotify 
      } 
      } 
     ] 
     } 

wo action.meta.index Index der Array-Element ist ich mit einem anderen Inhalt ersetzt werden soll das Objekt, aber ich glaube, das ersetzt nur ganze Reihe dieser ein Objekt, das ich vorbei bin. Ich dachte auch an die Verwendung von .splice(), aber das würde nur das Array mutieren?

+1

Werfen Sie auch einen Blick auf Unveränderlichkeit Helfer der Reaktion - https://facebook.github.io/ react/docs/update.html Sie sind nicht so schwer zu benutzen, wie sie aussehen und macht wirklich Ihren Code einfacher zu lesen. – Andreyco

Antwort

4

Splice mutieren Sie das Array, das Sie verwenden müssen Slice. Und Sie müssen auch das geschnittene Stück concat.

return Object.assign({}, state, { 
     contents: 
      state.contents.slice(0,action.meta.index) 
      .concat([{ 
      content_type: 7, 
      content_body: { 
       album_artwork_url: action.payload.data.album.images[1].url, 
       preview_url: action.payload.data.preview_url, 
       title: action.payload.data.name, 
       subtitle: action.payload.data.artists[0].name, 
       spotify_link: action.payload.data.external_urls.spotify 
      } 
      }]) 
      .concat(state.contents.slice(action.meta.index + 1)) 
    } 
+0

Bearbeitet .Ich denke, dass Sie versuchen, den gesamten Status zu senden, wobei sich der Inhalt geändert hat. Verwenden Sie Object.assign also, um einen neuen Status zu senden, und wenn in Object.assign mehrere Quellen für denselben Schlüssel vorhanden sind, gewinnt die letzte Quelle. – sapy

8

Nur auf @ sapy Antwort zu bauen, die die richtige ist. Ich wollte Ihnen ein weiteres Beispiel zeigen, wie Sie eine Eigenschaft eines Objekts in einem Array in Redux ändern können, ohne den Zustand zu verändern.

Ich hatte ein Array von orders in meinem Zustand. Jede order ist ein Objekt, das viele Eigenschaften und Werte enthält. Ich wollte jedoch nur die note Eigenschaft ändern. So ein Ding wie diese

let orders = [order1_Obj, order2_obj, order3_obj, order4_obj]; 

wo zum Beispiel order3_obj = {note: '', total: 50.50, items: 4, deliverDate: '07/26/2016'};

Also in meinem Reducer, ich den folgenden Code hatte:

return Object.assign({}, state, 
{ 
    orders: 
    state.orders.slice(0, action.index) 
    .concat([{ 
     ...state.orders[action.index], 
     notes: action.notes 
    }]) 
    .concat(state.orders.slice(action.index + 1)) 
    }) 

So im Wesentlichen, tun Sie Folgendes:

1) Trennen Sie das Array vor order3_obj, so [order1_Obj, order2_obj]

2) Concat (dh hinzufügen, in) der order3_obj bearbeitet von den drei Punkt ... Spread-Operator und die besondere Eigenschaft, die Sie (dh note)

3) Concat in den Rest der Aufträge Array .concat ändern möchten, und .slice am Ende .concat(state.orders.slice(action.index + 1)) das ist alles nach order3_obj (in diesem Fall order4_obj ist das einzige übrig).

+2

Vielen Dank! Super hilfreiche Erklärung – Alastair

+0

das hat mir sehr geholfen. ty for this – user1189352

5

Beachten Sie, dass Array.prototype.map() (docs) tut nicht das ursprüngliche Array mutieren, so dass es eine andere Option sieht vor:

const INITIAL_STATE = { 
    contents: [ {}, {}, {}, etc.. ], 
    meta: {} 
} 

// Assuming this action object design 
{ 
    type: MY_ACTION, 
    data: { 
    // new content to replace 
    }, 
    meta: { 
    index: /* the array index in state */, 
    } 
} 

function myReducer(state = INITIAL_STATE, action) { 
    switch (action.type) { 
    case MY_ACTION: 
     return { 
     ...state, 
     // optional 2nd arg in callback is the array index 
     contents: state.contents.map((content, index) => { 
      if (index === action.meta.index) { 
      return action.data 
      } 

      return content 
     }) 
     } 
    } 
} 
+1

Definitiv die eleganteste Lösung. –