简体   繁体   English

反应推送数组中的唯一对象

[英]react push unique objects in array

I have a function that is supposed to add unique elements to an array: 我有一个应该向数组添加唯一元素的函数:

addLanguage = (val) => {

    for(let i=0; i< val.length; i++){
        console.log(val[i].id)
        if(this.state.createNewDeliveryData.languages.indexOf(val[i].id === -1)){
             this.state.createNewDeliveryData.languages.push(val[i])
        }
    }
}

the argument 'val' each time gets an array with appended elements (I have a multi select box on UI from where I add languages), that's why in If loop I am trying to check if my languages array already has that specific element. 参数val每次都会得到一个带有附加元素的数组(我从中添加语言的UI上有一个多选框),这就是为什么在If循环中我试图检查我的语言数组是否已经具有该特定元素。 However this has no effect and at the end my languages array contains same elements ie same element is added twice or thrice etc. on subsequent calls. 但是,这没有任何效果,最后,我的语言数组包含相同的元素,即在后续调用中将相同的元素添加两次或三次。

['German']
['German', 'German', 'Arabic']
...

What am I doing wrong? 我究竟做错了什么?

You are looking for the index of false in your array. 您正在寻找数组中的false索引。 That's because, indexOf(val[i].id === -1) will always check indexOf(false) which is -1. 这是因为indexOf(val[i].id === -1)将始终检查indexOf(false) So you re-add each language. 因此,您需要重新添加每种语言。

You are probably after an algorithm more similar to this: 您可能正在寻找一种更类似于此的算法:

addLanguage = (val) => {
    // Get a copy of the languages state. 
    const languages = [...this.state.createNewDeliveryData.languages];
    for(let i=0; i< val.length; i++){
        if(languages.indexOf(val[i].id) === -1) { // notice that there is a parenthesis after `id`.
            languages.push(val[i].id)
        }
    }
    this.setState({createNewDeliveryData: {languages}}); // update state and trigger re-render if there are new languages. 
}

Note that you should always use setState to mutate the state in react. 请注意,您应始终使用setState更改react中的状态。

You have a few issues with your code: 您的代码有一些问题:

  • First of all, never, ever mutate this.state directly. 首先, 永远 this.state直接this.state It is anti-pattern and may yield undesired results. 这是反模式,可能会产生不希望的结果。 Use this.setState() instead. 请改用this.setState()

  • There is no need to do indexOf in a loop. 无需在循环中执行indexOf indexOf will iterate the array and return the index of the searched item, or -1 if it was not in the array. indexOf将迭代该数组并返回搜索到的项目的索引;如果它不在数组中,则返回-1

  • You have to create a copy for the this.state.createNewDeliveryData object and for the languages array. 您必须为this.state.createNewDeliveryData对象 languages数组创建一个副本。


That said, one solution could be: 也就是说,一种解决方案可能是:

addLanguage = (val) => {
  if(this.state.createNewDeliveryData.languages.indexOf(val) === -1) {
    let obj = Object.assign({}, this.state.createNewDeliveryData);  //shallow-copy object
    let arr = obj.languages.slice();  //copy array
    arr.push(val);  //push the value
    obj.languages = arr;  //assign the new array to our copied object
    this.setState({createNewDeliveryData: obj});  //replace the old object with the new
  }
}

or in a more compact form: 或更紧凑的形式:

addLanguage = (val) => {
  if(this.state.createNewDeliveryData.languages.indexOf(val) === -1) {
    let obj = Object.assign({}, this.state.createNewDeliveryData);  //shallow-copy object
    obj.languages = obj.languages.slice().push(val);
    this.setState({createNewDeliveryData: obj});  //replace the old object with the new
  }
}

Instead of checking each element in a loop, you could just use Set object to remove every duplicated element. 无需检查循环中的每个元素,您可以使用Set对象删除每个重复的元素。

Note : I assume that the val variable is an array. 注意 :我假设val变量是一个数组。

addLanguage = (val) => [...new Set(val)];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM