React:当状态是对象数组时更新状态

IT技术 reactjs ecmascript-6
2021-03-27 04:14:18

我有一组处于状态的对象:

this.state = {
  items: [
    {id: 1, someattr: "a string", anotherattr: ""},
    {id: 2, someattr: "another string", anotherattr: ""},
    {id: 3, someattr: "a string", anotherattr: ""},
  ]
}

我需要能够根据 id 属性搜索 items 数组,然后更新对象属性。

我可以使用 id 参数通过数组filteringfinding在数组上获取对象

我遇到的问题是更新数组,然后更新状态而不发生突变。

//make sure we're not mutating state directly by using object assign
const items = Object.assign({}, this.state.items);
const match = items.find((item) => item.id === id);

在这一点上,我有一个匹配的对象,可以使用对象传播更新它的属性:

const matchUpdated = { ...match, someattr: 'a new value'};

我的问题是如何更新状态以matchUpdated覆盖初始查找操作返回的对象?

6个回答

您的更新功能如下所示

updateItem(id, itemAttributes) {
  var index = this.state.items.findIndex(x=> x.id === id);
  if (index === -1)
    // handle error
  else
    this.setState({
      items: [
         ...this.state.items.slice(0,index),
         Object.assign({}, this.state.items[index], itemAttributes),
         ...this.state.items.slice(index+1)
      ]
    });
}

你像这样使用它

this.updateItem(2, {someattr: 'a new value'});

粗对吗?


如果您继续以这种方式构建复杂的应用程序,您通常会非常头疼。我建议您研究redux或其他一些更适合解决这些问题的 Flux 实现。

Redux 使用 state reducer 的概念,每个都在应用程序状态的特定切片上工作。这样你就不必在每次想要影响深刻变化时手动挖掘整个状态。

Redux 的创建者 Dan Abramov 制作了两个免费在线视频课程。Dan 是一位出色的老师,在使用 Redux 模式一个下午后,我对它感到很满意。

我自己刚刚使用 findIndex 提出了一个类似的解决方案!不能更同意使用 redux,我一直在使用它,但在这种情况下我不能使用它。
2021-05-22 04:14:18
我的意思是,我宁愿在这个答案中一团糟而不是 redux
2021-05-23 04:14:18
如果数组长度在 50-80 左右,这意味着您每次与 .name 文本框交互时都在使用 .find() ,这是一种非常糟糕的方法。
2021-05-26 04:14:18

如果你想使用一个函数,这就是我要做的......

const[array,setArray]= useState([
    {id: 1, value: "aws", othervalue: "was"},
    {id: 2, value: "goo", othervalue: "nano"},
    {id: 3, value: "micro", othervalue: "marcro"},
])

const updateItem =(id, whichvalue, newvalue)=> {
    let index = array.findIndex(x=> x.id === id); 
/*this line is only neccessay if your element's id 
isn't its postion/index in the array or related to it.
In the case that it is, use the id as the index, or run the function
(binary/hash) that relates the id to that position/index to find the index.
*/
    if (index !== -1){
        let temporaryarray = array.slice();
        temporaryarray[index][whichvalue] = newvalue;
        setArray(temporaryarray);
    }
    else {
        console.log('no match');
    }
}
    /* --longer version--
    var index = array.findIndex(x=> x.id === id);
    let g = array[index]
    g[whichvalue] = newvalue
    if (index === -1){
        console.log('no match')
    }
    else {
        setArray(
            [
            ...array.slice(0,index),
            g,
            ...array.slice(index+1)
            ]
        );
    }
    */
    
//how to use the function    
onPress={()=>updateItem(2,'value','John Lemon')}
onPress={()=>updateItem(1,'othervalue','Stringo Stra')}

该函数的第一个输入是项目的 id。

该函数的第二个输入是您希望更改的属性。

该函数的第三个输入是该属性的新值。

如果您使用功能组件和 useState 钩子,您可以轻松使用 map,只要您不介意替换整个对象

const [items, setItems] = useState ([
    {id: 1, someattr: "a string", anotherattr: ""},
    {id: 2, someattr: "another string", anotherattr: ""},
    {id: 3, someattr: "a string", anotherattr: ""},
])

setItems (
    items.map((item) => {
        return item.id === updatedItem.id? updatedItem: item;
    })
); 

添加到 Mulan 的答案,您可以使用Object spreadObject.assign()

updateItem(id, itemAttributes) {
  var index = this.state.items.findIndex(x=> x.id === id);
  if (index === -1)
    // handle error
  else
    this.setState({
      items: [
         ...this.state.items.slice(0,index),
        { ...this.state.items[index], itemAttributes },  
         ...this.state.items.slice(index+1)
      ]
    });
}

你像这样使用它

this.updateItem(2, {someattr: 'a new value'});

您可以遍历状态数组对象的值并替换状态。在循环中,您可以决定要应用新值的记录(如果不是全部)。

this.state = {
  items: [
    {id: 1, someattr: "a string", anotherattr: ""},
    {id: 2, someattr: "another string", anotherattr: ""},
    {id: 3, someattr: "a string", anotherattr: ""},
  ]
}

//回答

const newState = Object.assign({}, this.state);
   
newState.items.forEach(element => {

  element.someattr= "I like it a lot";

});

this.setState(newState);