web-dev-qa-db-ja.com

状態を変更せずに配列項目を別のものに置き換えます

これは私の状態の例がどのように見えるかです:

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

インデックスを知っているコンテンツ配列内のアイテムを何らかの方法で置き換えることができるようにする必要があります。

_      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
            }
          }
        ]
      }
_

ここで、_action.meta.index_は、別のコンテンツオブジェクトで置き換えたい配列項目のインデックスですが、これは、配列全体を、渡したこの1つのオブジェクトに置き換えるだけだと思います。私は.splice()の使用も考えましたが、それは配列を変更するだけですか?

15
Ilja

Splice使用する必要がある配列を変更しますSlice。また、スライスしたピースを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))
  }
5
sapy

Array.prototype.map()docs )は、元の配列を変更しないので、別のオプションを提供することに注意してください。

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

正しい答えである@sapyの答えに基づいて構築してください。状態を変更せずにReduxの配列内のオブジェクトのプロパティを変更する方法の別の例を紹介したいと思います。

私の状態ではordersの配列がありました。各orderは、多くのプロパティと値を含むオブジェクトです。ただし、noteプロパティのみを変更したいと思っていました。だからこのようなもの

_let orders = [order1_Obj, order2_obj, order3_obj, order4_obj];
_

たとえば、_order3_obj = {note: '', total: 50.50, items: 4, deliverDate: '07/26/2016'};_

したがって、私のレデューサーには、次のコードがありました。

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

したがって、基本的には、次のことを行っています。

1)_order3_obj_の前に配列をスライスして、_[order1_Obj, order2_obj]_

2)編集した_order3_obj_を3つのドット_..._スプレッド演算子と変更する特定のプロパティ(つまりnote)を使用して連結(つまりアドイン)します。

3)_.concat_の後のすべてである.concat(state.orders.slice(action.index + 1))の最後に_.slice_および_order3_obj_を使用して、残りの注文配列を連結します(この場合は_order4_obj_は残り1つ)。

12
HussienK