Reputation: 5356
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. However this has no effect and at the end my languages array contains same elements i.e. same element is added twice or thrice etc. on subsequent calls.
['German']
['German', 'German', 'Arabic']
...
What am I doing wrong?
Upvotes: 2
Views: 6988
Reputation: 59511
You have a few issues with your code:
First of all, never, ever mutate this.state
directly. It is anti-pattern
and may yield undesired results. Use this.setState()
instead.
There is no need to do indexOf
in a loop. indexOf
will iterate the array and return the index of the searched item, or -1
if it was not in the array.
You have to create a copy for the this.state.createNewDeliveryData
object and for the languages
array.
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
}
}
Upvotes: 2
Reputation: 15335
You are looking for the index of false
in your array. That's because, indexOf(val[i].id === -1)
will always check indexOf(false)
which is -1. 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.
Upvotes: 3
Reputation: 41893
Instead of checking each element in a loop, you could just use Set
object to remove every duplicated element.
Note: I assume that the val
variable is an array.
addLanguage = (val) => [...new Set(val)];
Upvotes: 2