How to avoid adding to an array if element already exists

10,094

The right condition is

if (!(this.state.likes.filter(e => e.name === person.name).length > 0)) {
  // your code
}

The meaning of the condition is:

this.state.likes.filter(e => e.name === person.name).length > 0) This will filter out the array only when an element of the array matches with the provided person object name. It points out that the person is already present in the array

The ! is used to check the opposite condition, because you want enter in your if statement only if person does not exists

EDIT Reading better your code, this could be accomplished with a simpler, cleaner method:

  addPerson = (person) => {
    let filteredPerson = this.state.likes.filter(like => like.name !== person.name);
    this.setState({
      likes: [...filteredPerson, person]
    })        
  }

Check out this working snippet: https://stackblitz.com/edit/react-jxebwg

Share:
10,094

Related videos on Youtube

kayak
Author by

kayak

I'm learning React and JavaScript. Front-end Developer to be.

Updated on June 04, 2022

Comments

  • kayak
    kayak almost 2 years

    I'm making Add to favorite function in React. Thanks to everyone's help I could somehow make that work except for toggling like and dislike. I coded like "likes: this.state.likes.filter(e => e.name !== person.name)" just because someone advised me to code so. To be honest I don't understand the code above maybe because it's ES6 syntax. How does it look like in ES5? And right now that code is not working, elements are not added to the array properly. How do I fix this code?

    import React from 'react';
    import axios from 'axios';
    import IcoMoon from 'react-icomoon';
    
    export default class PersonList extends React.Component {
    
        state = {
            persons: [],
            likes: []
        }
    
        componentDidMount() {
            axios.get(`https://jsonplaceholder.typicode.com/users`)
                .then(res => {
                    const persons = res.data;
                    this.setState({ persons });
                })
        }
    
        handleClick = person => {
    
            if (this.state.likes.filter(e => e.name === person.name).length > 0) {
    
                this.setState({
                    likes: this.state.likes.filter(e => e.name !== person.name)
                });
    
                console.log(this.state.likes);
                return;
            }
    
            this.setState({
                likes: [...this.state.likes, person]
            });       
        };
    
        likesTemplate = item => <li key={item}>{item}</li>;
    
        renderLikes = () => {
            return this.state.likes.map(i => this.likesTemplate(i));
        }
    
        render() {
            return (
                <div>
                    {this.state.persons.map(person => {
                    return <li key={person.name}><IcoMoon icon="heart" onClick={() => {this.handleClick(person.name)}} />{person.name}</li>}
                )}
    
                <h2>Favorite Person</h2>
                <ul>
                    {this.renderLikes()}
                </ul>
                </div>
            )
        }
    }
    
    • Joe Taras
      Joe Taras almost 5 years
      Have you tried with Array​.prototype​.includes() to check if an element exists in an array. See here: developer.mozilla.org/it/docs/Web/JavaScript/Reference/…
    • buffy
      buffy almost 5 years
      Using Set instead of array could be a good idea, too. Avoiding duplicates is the nature of a set afterall. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • kayak
      kayak almost 5 years
      I tried it and it works! "if (this.state.likes.includes(person)) {". Now my problem is I can't figure out how to remove duplicated element in the array. I'm trying like "this.setState({ likes: this.state.likes.splice(person) });" but it won't work :(
    • buffy
      buffy almost 5 years
      try this.state.likes.splice(this.state.likes.indexOf(person), 1)
    • kayak
      kayak almost 5 years
      Tried the code above but it seems like I messed up everything. If I click for the first time the array is still empty, and if I click another person then previous person is added to the array.
    • Chris Ngo
      Chris Ngo almost 5 years
      @kayak, I just wrote you solution. Let me know if that's helpful!
  • Mosè Raguzzini
    Mosè Raguzzini almost 5 years
    Fixed, a parenthesis issue. You cal also check alternatively that length should be < 1, without !
  • kayak
    kayak almost 5 years
    So if the array does not include person, then splice? Maybe it's opposite?
  • kayak
    kayak almost 5 years
    Thank you for your detailed explanation. I didn't know .filter removes specific element. However the code is not working as I intended. The toggle happens even when I click other icons.
  • kayak
    kayak almost 5 years
    If I click a person and click again it sure toggles, but if I another person before I toggle, the likes array turns empty. Btw thank you for the link. That service looks useful.
  • Chris Ngo
    Chris Ngo almost 5 years
    @kayak I'm not sure what you mean by other icons? Do you mean the icon that belongs to a different like changes when you click on an icon?
  • kayak
    kayak almost 5 years
    Sorry for the confusion. Maybe I should do "if (likes.map(like => like).includes(person))" ? I removed all the ".name" and it finally worked!
  • kayak
    kayak almost 5 years
    Not sure if "if (likes.map(like => like).includes(person))" syntax is correct though..
  • Chris Ngo
    Chris Ngo almost 5 years
    @kayak ahh okay I see what went wrong here. You're already passing person.name into your handleClick function when you render these icons. Also it looks like the likes array is just an array of strings which are just the person names. I thought it would be an object. In this case, we only need .includes(). Let me update my answer to clean up the solution.
  • Chris Ngo
    Chris Ngo almost 5 years