我有一个以状态存储的项目集合:
this.state = {
items: [
{ name: "foo", description: "a foo", index: 0 },
{ name: "bar", description: "a bar", index: 1 },
{ name: "herp", description: "a herp", index: 2 },
{ name: "derp", description: "a derp", index: 3 }
]
};
index
属性表示集合中每个项目的序号位置。在某些时候,我需要重新订购这些项目。例如," derp"可能需要移到前面,因此需要更新其他项的索引:
{ name: "derp", description: "a derp", index: 0 },
{ name: "bar", description: "a bar", index: 1 },
{ name: "herp", description: "a herp", index: 2 },
{ name: "foo", description: "a foo", index: 3 }
我目前正使用update
包中的immutability-helper
更新状态。但是,我确信这不是正确的方法(虽然它有效):
// originalIndex is a variable holding the original index
// newIndex is a variable holding the new index
// initialise updatedItems so we can update within the loop
let updatedItems = update(this.state.items, { [originalIndex]: {'index': {$set: newIndex}}});
for (var i = newIndex; i < this.state.items.length; i++) {
if (i !== originalIndex) {
updatedItems = update(updatedItems, { [i]: {'index': {set$: parseInt(this.state.items[i].index) + 1}}});
}
}
这感觉就像一场大规模的黑客攻击。
我的问题是,是否可以使用条件逻辑调用更新,因此可以用一次更新调用替换此循环吗?
答案 0 :(得分:2)
假设我们从每个项目中提取index
属性,您可以像这样创建新列表:
const items = this.state.items.slice();
const value = items[oldIndex];
items.splice(oldIndex, 1); // remove the one you want to move
items.splice(newIndex, 0, value); // add it back to the desired index
this.setState({ items });
也就是说,使用slice制作列表的(浅)副本,然后使用splice交换元素。
由于您一次只移动一个元素,因此可以使用以下方法保存一行:
const [value] = items.splice(oldIndex, 1);
这会将splice
返回的数组的第一个元素指定给value
。
如果你想保留index
(为什么?),那么你需要重新分配索引:
this.setState({ items: items.map((item, index) => ({ ...item, index })) });
答案 1 :(得分:1)
为什么不先在render()上对项目进行排序:
render(){
let toDisplay = this.state.items.sort( (a,b) => {
if (a.index <= b.index) {
return -1;
}
if (a.index > b.index) {
return 1;
}
return 0;
});
return(
<div className='foo'>
{
toDisplay.map((item, i) => {
return(
<div className="bar" key={i}>{ item.name }</div>
);
})
}
</div>
);
}
然后,您只能使用以下命令更新state.items:
this.setState({
items: yourUpdatedItems
});