问题
This is how example of my state looks:
const INITIAL_STATE = {
contents: [ {}, {}, {}, etc.. ],
meta: {}
}
I need to be able and somehow replace an item inside contents array knowing its index, I have tried:
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
}
}
]
}
where action.meta.index
is index of array item I want to replace with another contents object, but I believe this just replaces whole array to this one object I'm passing. I also thought of using .splice()
but that would just mutate the array?
回答1:
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))
}
回答2:
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
})
}
}
}
回答3:
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).
来源:https://stackoverflow.com/questions/35362460/replace-array-item-with-another-one-without-mutating-state