33

我正在使用 ... spread 语法替换反应状态数组中的项目。这有效:

let newImages = [...this.state.images]
newImages[4] = updatedImage
this.setState({images:newImages})

是否有可能在一行代码中做到这一点?像这样的东西?(这显然不起作用......)

this.setState({images: [...this.state.images, [4]:updatedImage})
4

8 回答 8

46

使用Array.slice

this.setState({images: [...this.state.images.slice(0, 4), updatedImage, ...this.state.images.slice(5)]})

从原始帖子编辑:更改 slice 方法的第二个参数中的 3 oa 4 ,因为第二个参数指向超出最后一个保留的数组成员,它现在正确回答了原始问题。

于 2017-08-14T11:49:32.633 回答
25

Object.assign做这项工作:

this.setState({images: Object.assign([], this.state.images, {4: updatedImage}));

...但涉及一个临时对象(最后的那个)。尽管如此,只有一个临时对象......如果你这样做slice并分散数组,它会涉及更多的临时对象(来自的两个数组slice,它们的迭代器,通过调用迭代器的next函数创建的结果对象[在...句柄内], ETC。)。

它之所以有效,是因为普通的 JS 数组并不是真正的数组1 (这当然需要优化),它们是具有一些特殊功能的对象。它们的“索引”实际上是符合某些标准的属性名称2。所以在那里,我们展开this.state.images到一个新数组中,将它Object.assign作为目标传递给一个对象,并给出Object.assign一个具有名为的属性的对象"4"(是的,它最终是一个字符串,但我们可以将它写为一个数字)我们要更新的值。

现场示例:

const a = [0, 1, 2, 3, 4, 5, 6, 7];
const b = Object.assign([], a, {4: "four"});
console.log(b);

如果4可以是变量,那很好,您可以使用计算属性名称(ES2015 中的新功能):

let n = 4;
this.setState({images: Object.assign([], this.state.images, {[n]: updatedImage}));

注意[]周围n

现场示例:

const a = [0, 1, 2, 3, 4, 5, 6, 7];
const index = 4;
const b = Object.assign([], a, {[index]: "four"});
console.log(b);


1披露:这是我贫血的小博客上的一篇文章。

2这是项目符号列表之后的第二段:

整数索引是字符串值的属性键,它是规范的数字字符串(参见 7.1.16),其数值为+0或正整数 ≤ 2 53 -1。数组索引是一个整数索引,其数值i在 +0 ≤ i < 2 32 -1 范围内。

所以这Object.assign和你的 create-the-array-then-update-index-4 一样。

于 2017-08-14T11:47:35.757 回答
12

您可以使用地图:

const newImages = this.state.images
  .map((image, index) => index === 4 ? updatedImage : image)
于 2017-08-14T11:48:16.840 回答
7

您可以将数组转换为对象(...array1),替换项目([1]:"seven"),然后将其转换回数组(Object.values):

array1 = ["one", "two", "three"];
array2 = Object.values({...array1, [1]:"seven"});
console.log(array1);
console.log(array2);

于 2020-05-12T23:03:16.483 回答
3

这是我的自我解释非单行

 const wantedIndex = 4;
 const oldArray = state.posts; // example

 const updated = {
     ...oldArray[wantedIndex], 
     read: !oldArray[wantedIndex].read // attributes to change...
 } 

 const before = oldArray.slice(0, wantedIndex); 
 const after = oldArray.slice(wantedIndex + 1);

 const menu = [
     ...before,  
     updated,
     ...after
 ]
于 2018-08-08T13:37:43.397 回答
2

我参考了@Bardia Rastin 解决方案,我发现该解决方案在索引值处有错误(它替换了索引 3 但不是 4 处的项目)。

如果要替换具有索引值的项目,索引,答案应该是

this.setState({images: [...this.state.images.slice(0, index), updatedImage, ...this.state.images.slice(index + 1)]})

this.state.images.slice(0, index)是一个新数组,其项目从 0 开始到索引 - 1(不包括索引)

this.state.images.slice(index)是一个新数组,其项目从index 开始,然后

要正确替换索引 4 处的项目,答案应该是:

this.setState({images: [...this.state.images.slice(0, 4), updatedImage, ...this.state.images.slice(5)]})
于 2019-10-26T09:53:11.780 回答
1

先找到索引,这里我用图片文档id docId作为说明:

const index = images.findIndex((prevPhoto)=>prevPhoto.docId === docId)
this.setState({images: [...this.state.images.slice(0,index), updatedImage, ...this.state.images.slice(index+1)]})
于 2021-10-05T13:43:17.763 回答
0

我已经尝试了很多使用扩展运算符。我认为当您使用 splice() 时,它会更改主数组。所以我发现的解决方案是在新变量中克隆数组,然后使用扩展运算符将其拆分。我用的例子。

var cart = [];

function addItem(item) {
    let name = item.name;
    let price = item.price;
    let count = item.count;
    let id = item.id;

    cart.push({
        id,
        name,
        price,
        count,
    });

    return;
}

function removeItem(id) {
    let itemExist = false;
    let index = 0;
    for (let j = 0; j < cart.length; j++) {
        if (cart[j].id === id) { itemExist = true; break; }
        index++;
    }
    if (itemExist) {
        cart.splice(index, 1);
    }
    return;
}

function changeCount(id, newCount) {
    let itemExist = false;
    let index = 0;
    for (let j = 0; j < cart.length; j++) {
        console.log("J: ", j)
        if (cart[j].id === id) {
            itemExist = true;
            index = j;
            break;
        }
    }
    console.log(index);
    if (itemExist) {
        let temp1 = [...cart];
        let temp2 = [...cart];
        let temp3 = [...cart];
        cart = [...temp1.splice(0, index),
            {
                ...temp2[index],
                count: newCount
            },
            ...temp3.splice(index + 1, cart.length)
        ];
    }

    return;
}

addItem({
    id: 1,
    name: "item 1",
    price: 10,
    count: 1
});
addItem({
    id: 2,
    name: "item 2",
    price: 11,
    count: 1
});
addItem({
    id: 3,
    name: "item 3",
    price: 12,
    count: 2
});
addItem({
    id: 4,
    name: "item 4",
    price: 13,
    count: 2
});

changeCount(4, 5);
console.log("AFTER CHANGE!");
console.log(cart);
于 2022-01-29T21:12:36.310 回答