Replace array item with another one without mutating state

心不动则不痛 提交于 2019-11-30 11:41:49

Splice mutate the array you need to use Slice . And you also need to concat the sliced piece .

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))
  }

Note that Array.prototype.map() (docs) does not mutate the original array so it provides another option:

 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
         })
       }
   }
 }

Just to build on @sapy's answer which is the correct one. I wanted to show you another example of how to change a property of an object inside an array in Redux without mutating the state.

I had an array of orders in my state. Each order is an object containing many properties and values. I however, only wanted to change the note property. So some thing like this

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

where for example order3_obj = {note: '', total: 50.50, items: 4, deliverDate: '07/26/2016'};

So in my Reducer, I had the following code:

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 essentially, you're doing the following:

1) Slice out the array before order3_obj so [order1_Obj, order2_obj]

2) Concat (i.e add in) the edited order3_obj by using the three dot ... spread operator and the particular property you want to change (i.e note)

3) Concat in the rest of the orders array using .concat and .slice at the end .concat(state.orders.slice(action.index + 1)) which is everything after order3_obj (in this case order4_obj is the only one left).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!