用另一个不改变状态的数组项替换数组项
Posted
技术标签:
【中文标题】用另一个不改变状态的数组项替换数组项【英文标题】:Replace array item with another one without mutating state 【发布时间】:2016-05-23 14:15:54 【问题描述】:这是我的状态示例的外观:
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
是我想用另一个内容对象替换的数组项的索引,但我相信这只是将整个数组替换为我正在传递的这个对象。我也想过使用.splice()
,但这只会改变数组吗?
【问题讨论】:
另外,看看 React 的 Immutability 助手 - facebook.github.io/react/docs/update.html 它们并不像看起来那么难使用,而且确实让你的代码更容易阅读。 【参考方案1】:请注意,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
)
【讨论】:
绝对是最优雅的解决方案。【参考方案2】:只是以@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';
所以在我的 Reducer 中,我有以下代码:
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) 使用三个点...
扩展运算符和您要更改的特定属性(即note
)连接(即添加)编辑的order3_obj
3) 在剩余的订单数组中使用.concat
和.slice
连接,最后.concat(state.orders.slice(action.index + 1))
是order3_obj
之后的所有内容(在这种情况下,order4_obj
是唯一剩下的一个)。
【讨论】:
非常感谢!超级有用的解释 这对我帮助很大。为这个【参考方案3】: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))
【讨论】:
已编辑。我猜您正在尝试发送整个状态,内容值已更改。因此,使用 Object.assign 发送新的 state ,如果 Object.assign 中的同一键有多个来源,则最后一个来源获胜。以上是关于用另一个不改变状态的数组项替换数组项的主要内容,如果未能解决你的问题,请参考以下文章
在reactjs中删除重复项后如何从状态值和setstate创建数组